for (Thread thread : threads) {
if (thread != null) {
ClassLoader ccl = thread.getContextClassLoader();
- if (ccl != null && ccl == this) {
+ if (ccl == this) {
// Don't warn about this thread
if (thread == Thread.currentThread()) {
continue;
boolean remove = false;
// Check the key
Object key = ((Reference<?>) table[j]).get();
- if (this.equals(key) || (key != null &&
- this == key.getClass().getClassLoader())) {
+ if (this.equals(key) ||
+ isLoadedByThisWebAppClassLoader(key)) {
remove = true;
}
// Check the value
table[j].getClass().getDeclaredField("value");
valueField.setAccessible(true);
Object value = valueField.get(table[j]);
- if (this.equals(value) || (value != null &&
- this == value.getClass().getClassLoader())) {
+ if (this.equals(value) ||
+ isLoadedByThisWebAppClassLoader(value)) {
remove = true;
}
if (remove) {
Object[] args = new Object[5];
args[0] = contextName;
if (key != null) {
- args[1] = key.getClass().getCanonicalName();
+ args[1] = getPrettyClassName(key.getClass());
try {
args[2] = key.toString();
} catch (Exception e) {
}
}
if (value != null) {
- args[3] = value.getClass().getCanonicalName();
+ args[3] = getPrettyClassName(value.getClass());
try {
args[4] = value.toString();
} catch (Exception e) {
}
}
+ private String getPrettyClassName(Class<?> clazz) {
+ String name = clazz.getCanonicalName();
+ if (name==null){
+ name = clazz.getName();
+ }
+ return name;
+ }
+
+ /**
+ * @param o object to test
+ * @return <code>true</code> if o has been loaded by the current classloader
+ * or one of its descendants.
+ */
+ private boolean isLoadedByThisWebAppClassLoader(Object o) {
+ if (o == null) {
+ return false;
+ }
+ ClassLoader cl = o.getClass().getClassLoader();
+ while (cl != null) {
+ if(cl == this) {
+ return true;
+ }
+ cl = cl.getParent();
+ }
+ return false;
+ }
+
/*
* Get the set of current threads as an array.
*/
<section name="Tomcat 7.0.6 (markt)">
<subsection name="Catalina">
<changelog>
+ <add>
+ <bug>48837</bug>: Extend thread local memory leak detection to include
+ classes loaded by subordinate class loaders to the web
+ application's class loader such as the Jasper class loader. Based
+ on a patch by Sylvain Laurent. (markt)
+ </add>
<fix>
<bug>49650</bug>: Remove unnecessary entries package.access property
defined in catalina.properties. Patch provided by Owen Farrell. (markt)