google-code-export / morphia

Automatically exported from code.google.com/p/morphia
1 stars 0 forks source link

Memory leak of MappedClass when using BasicDAO #385

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What version are you using? (Morphia/Driver/MongoDB)
morphia-0.99.1-SNAPSHOT
mongo-2.7.2

I see a leak of MappedClass and the associated MappedFields when using 
BasicDAO.  I've simplified it down to simply creating an instance of a class 
that extends BasicDAO.  Running GC and collecting a heap dump shows an extra 
MappedClass in the heap with every call to doGet in the code below.  Leaving 
all code as is, but modifying the DAO to  NOT extend BasicDAO and rather access 
the Datastore directly (w/ the instance retrieved from the MongoManager) clears 
up the leak.

public class TesterDao extends BasicDAO<Tester, ObjectId> {

    public TesterDao() {
        super(Tester.class, MongoManager.instance().getDb());
    }
}

public class MorphiaTestServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        TesterDao testerDao = new TesterDao();
    }
}

public class MongoManager {

    private static final MongoManager INSTANCE = new MongoManager();

    private final String MONGO_HOST = "localhost";
    private final int MONGO_PORT = 27017;

    private Datastore theDb = null;

    private MongoManager() {

        Mongo mongo;
        try {
            mongo = new Mongo(MONGO_HOST, MONGO_PORT);
            theDb = new Morphia()
                .map(Tester.class)
                .createDatastore(mongo, "MorphiaTest");
            theDb.ensureIndexes();

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (MongoException e) {
            e.printStackTrace();
        }           
    }

    public static MongoManager instance() {
        return INSTANCE;
    }

    public Datastore getDb() {
        return theDb;
    }
}
@Entity (noClassnameStored=true)
public class Tester {

    @Id
    private ObjectId id;

    private String name;

    public Tester() {}

    public Tester(String name) {
        this.name = name;
    }

    public ObjectId getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

Original issue reported on code.google.com by m...@thelevines.com on 3 Mar 2012 at 1:14

GoogleCodeExporter commented 9 years ago
Bumped into the same issue. After analyzing the heap dump we found the problem:

On each construction of a BasicDAO it calls "initType" which calls 
"addMappedClass" on the mapper itself. Which is valid from our point of view.

The mapper manages all mapped classes in its mappedClasses and 
mappedClassesByCollection collections. The memory leak occurs in Mapper:170, 
when MappedClass instances are added to sets in mappedClassesByCollection 
("mcs.add(mc)"). We got millions of entries in the sets of 
mappedClassesByCollection values.

Solution:
1) Override the hashCode method of MappedClass. Suggestion: return 
clazz.hashCode()
2) Make the mapper check if a Class is mapped already. Currently using BasicDAO 
it reflects and analyzes the entity class on each construction

Original comment by juri.ku...@gmail.com on 21 Jan 2013 at 2:20