[JAVA-1059] Memory leak in ClassAncestry Created: 19/Dec/13  Updated: 23/Jun/15  Resolved: 23/Jun/15

Status: Closed
Project: Java Driver
Component/s: BSON
Affects Version/s: 2.11.3
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Michel Yerly Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

ClassAncestry stores references to my classes (like enums that I use in the queries), never releases these references, which prevent the WebappClassloader and all the classes it loaded to be reclaimed by the garbage collector when I undeploy my webapp.

I'm currently working around using reflection.

@SuppressWarnings("unchecked")
public static void cleanupMongoDriver(ClassLoader webappClassLoader) {
 
	ClassLoader bsonLoader = ClassMap.class.getClassLoader();
	Class<?> clazz;
	try {
		clazz = Class.forName("org.bson.util.ClassAncestry", true, bsonLoader);
	} catch (ClassNotFoundException e) {
		return;
	}
 
	ConcurrentMap<Class<?>, List<Class<?>>> _ancestryCache;
	try {
		Field f = clazz.getDeclaredField("_ancestryCache");
		f.setAccessible(true);
		_ancestryCache = (ConcurrentMap<Class<?>, List<Class<?>>>) f.get(null);
	} catch (Exception e) {
		return;
	}
	List<Class<?>> toRemove = new ArrayList<Class<?>>();
	for (Class<?> c : _ancestryCache.keySet()) {
		if (c.getClassLoader() == webappClassLoader) {
			toRemove.add(c);
		}
	}
	for (Class<?> c : toRemove) {
		_ancestryCache.remove(c);
	}
}



 Comments   
Comment by Jeffrey Yemin [ 02/Jan/14 ]

It would be helpful if you could provide a working code snippet showing object mapper registration (not sure what you mean by this) and the use of enums for queries (the driver doesn't support enum's out of the box).

Comment by Michel Yerly [ 02/Jan/14 ]

As I could observe these are typically enums that I use for the queries. Also I registered custom deserializers to the object mapper.

Comment by Jeffrey Yemin [ 02/Jan/14 ]

That's interesting. What classes are ending up in the ancestry cache, and how might the driver have become aware of them? The only way I'm aware that application-defined classes can get into the static class ancestry registry if via BSON.addEncodingHook or BSON.addDecodingHook.

Comment by Michel Yerly [ 02/Jan/14 ]

No my app doesn't call BSON.clearAllHooks(). I think I shouldn't have to call this method as I'm not using BSON directly. If a call is really needed on webapp undeployment, I'd suggest something like:
Mongo.flushCache()
or
Mongo.releaseClassloader(Classloader cl)
Maybe using weak or soft references in the cache could do the job as well.

Comment by Jeffrey Yemin [ 30/Dec/13 ]

Does your app already call BSON.clearAllHooks()? It may make sense to clear ClassAncestry._ancestryCache in that method.

Generated at Thu Feb 08 08:53:42 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.