mirror of
https://github.com/EsotericSoftware/reflectasm.git
synced 2025-01-19 16:20:24 +08:00
Solved PermGen memory leak in AccessClassLoader
Solved the PermGen memory leak due to static strong references to the class loaders (and minor performance improvement avoiding call to Method.setAccessible() if unnecessary).
This commit is contained in:
parent
395008a0b8
commit
904c1dcc84
@ -1,34 +1,69 @@
|
||||
|
||||
package com.esotericsoftware.reflectasm;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
class AccessClassLoader extends ClassLoader {
|
||||
static private final ArrayList<AccessClassLoader> accessClassLoaders = new ArrayList();
|
||||
|
||||
// Weak-references to ClassLoaders, to avoid PermGen memory leaks for example
|
||||
// in AppServers/WebContainters if the reflectasm framework (including this class)
|
||||
// is loaded outside the deployed applications (WAR/EAR) using ReflectASM/Kryo
|
||||
// (exts, user classpath, etc).
|
||||
//
|
||||
// The key is the parent ClassLoader and the value is the AccessClassLoader
|
||||
// Both are weak-referenced in the HashTable.
|
||||
static private final WeakHashMap<ClassLoader, WeakReference<AccessClassLoader>> accessClassLoaders = new WeakHashMap<ClassLoader, WeakReference<AccessClassLoader>>();
|
||||
// Fast-path for classes loaded in the same ClassLoader than this Class
|
||||
static private final ClassLoader selfContextParentClassLoader = getParentClassLoader(AccessClassLoader.class);
|
||||
static private volatile AccessClassLoader selfContextAccessClassLoader = new AccessClassLoader(selfContextParentClassLoader);
|
||||
|
||||
static AccessClassLoader get (Class type) {
|
||||
ClassLoader parent = type.getClassLoader();
|
||||
synchronized (accessClassLoaders) {
|
||||
for (int i = 0, n = accessClassLoaders.size(); i < n; i++) {
|
||||
AccessClassLoader accessClassLoader = accessClassLoaders.get(i);
|
||||
if (accessClassLoader.getParent() == parent) return accessClassLoader;
|
||||
ClassLoader parent = getParentClassLoader(type);
|
||||
// 1. fast-path:
|
||||
if (selfContextParentClassLoader.equals(parent)) {
|
||||
if (selfContextAccessClassLoader==null) {
|
||||
// DCL with volatile semantics
|
||||
synchronized (accessClassLoaders) {
|
||||
if (selfContextAccessClassLoader==null)
|
||||
selfContextAccessClassLoader = new AccessClassLoader(selfContextParentClassLoader);
|
||||
}
|
||||
}
|
||||
return selfContextAccessClassLoader;
|
||||
}
|
||||
// 2. normal search:
|
||||
synchronized (accessClassLoaders) {
|
||||
WeakReference<AccessClassLoader> ref = accessClassLoaders.get(parent);
|
||||
if (ref!=null) {
|
||||
AccessClassLoader accessClassLoader = ref.get();
|
||||
if (accessClassLoader!=null) return accessClassLoader;
|
||||
else accessClassLoaders.remove(parent); // the value has been GC-reclaimed, but still not the key (defensive sanity)
|
||||
}
|
||||
if(parent == null) parent = ClassLoader.getSystemClassLoader();
|
||||
AccessClassLoader accessClassLoader = new AccessClassLoader(parent);
|
||||
accessClassLoaders.add(accessClassLoader);
|
||||
accessClassLoaders.put(parent, new WeakReference<AccessClassLoader>(accessClassLoader));
|
||||
return accessClassLoader;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove (ClassLoader parent) {
|
||||
synchronized (accessClassLoaders) {
|
||||
for (int i = accessClassLoaders.size() - 1; i >= 0; i--) {
|
||||
AccessClassLoader accessClassLoader = accessClassLoaders.get(i);
|
||||
if (accessClassLoader.getParent() == parent) accessClassLoaders.remove(i);
|
||||
public static void remove (ClassLoader parent) {
|
||||
// 1. fast-path:
|
||||
if (selfContextParentClassLoader.equals(parent)) {
|
||||
selfContextAccessClassLoader = null;
|
||||
}
|
||||
else {
|
||||
// 2. normal search:
|
||||
synchronized (accessClassLoaders) {
|
||||
accessClassLoaders.remove(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int activeAccessClassLoaders() {
|
||||
int sz = accessClassLoaders.size();
|
||||
if (selfContextAccessClassLoader!=null) sz++;
|
||||
return sz;
|
||||
}
|
||||
|
||||
private AccessClassLoader (ClassLoader parent) {
|
||||
super(parent);
|
||||
@ -55,4 +90,10 @@ class AccessClassLoader extends ClassLoader {
|
||||
}
|
||||
return defineClass(name, bytes, 0, bytes.length, getClass().getProtectionDomain());
|
||||
}
|
||||
|
||||
private static ClassLoader getParentClassLoader(Class type) {
|
||||
ClassLoader parent = type.getClassLoader();
|
||||
if (parent == null) parent = ClassLoader.getSystemClassLoader();
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user