fix cache Class avoid PermGen space OOM in dubbo3.0 (#7386)

* fix #6742 cache Class avoid PermGen space OOM

* optimization cache Class avoid PermGen space OOM

* optimization cache Class avoid PermGen space OOM

* Optimize Proxy WeakReference to SoftReference
This commit is contained in:
xiaoheng1 2021-04-13 14:31:56 +08:00 committed by GitHub
parent d1c043f57b
commit 8e5eac1acf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 43 additions and 10 deletions

View File

@ -20,7 +20,7 @@ import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.ReflectUtils;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.ref.SoftReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@ -50,6 +50,8 @@ public abstract class Proxy {
private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);
private static final String PACKAGE_NAME = Proxy.class.getPackage().getName();
private static final Map<ClassLoader, Map<String, Object>> PROXY_CACHE_MAP = new WeakHashMap<ClassLoader, Map<String, Object>>();
// cache class, avoid PermGen OOM.
private static final Map<ClassLoader, Map<String, Object>> PROXY_CLASS_MAP = new WeakHashMap<ClassLoader, Map<String, Object>>();
private static final Object PENDING_GENERATION_MARKER = new Object();
@ -103,8 +105,11 @@ public abstract class Proxy {
// get cache by class loader.
final Map<String, Object> cache;
// cache class
final Map<String, Object> classCache;
synchronized (PROXY_CACHE_MAP) {
cache = PROXY_CACHE_MAP.computeIfAbsent(cl, k -> new HashMap<>());
classCache = PROXY_CLASS_MAP.computeIfAbsent(cl, k -> new HashMap<>());
}
Proxy proxy = null;
@ -118,14 +123,38 @@ public abstract class Proxy {
}
}
if (value == PENDING_GENERATION_MARKER) {
try {
cache.wait();
} catch (InterruptedException e) {
// get Class by key.
Object clazzObj = classCache.get(key);
if (null == clazzObj || clazzObj instanceof Reference<?>) {
Class<?> clazz = null;
if (clazzObj instanceof Reference<?>) {
clazz = (Class<?>) ((Reference<?>) clazzObj).get();
}
if (null == clazz) {
if (value == PENDING_GENERATION_MARKER) {
try {
cache.wait();
} catch (InterruptedException e) {
}
} else {
cache.put(key, PENDING_GENERATION_MARKER);
break;
}
} else {
try {
proxy = (Proxy) clazz.newInstance();
return proxy;
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
} finally {
if (null == proxy) {
cache.remove(key);
} else {
cache.put(key, new SoftReference<>(proxy));
}
}
}
} else {
cache.put(key, PENDING_GENERATION_MARKER);
break;
}
}
while (true);
@ -190,7 +219,7 @@ public abstract class Proxy {
ccp.setClassName(pcn);
ccp.addField("public static java.lang.reflect.Method[] methods;");
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[] {InvocationHandler.class}, new Class<?>[0], "handler=$1;");
ccp.addDefaultConstructor();
Class<?> clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0]));
@ -204,6 +233,10 @@ public abstract class Proxy {
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
Class<?> pc = ccm.toClass();
proxy = (Proxy) pc.newInstance();
synchronized (classCache) {
classCache.put(key, new SoftReference<Class<?>>(pc));
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
@ -220,7 +253,7 @@ public abstract class Proxy {
if (proxy == null) {
cache.remove(key);
} else {
cache.put(key, new WeakReference<Proxy>(proxy));
cache.put(key, new SoftReference<Proxy>(proxy));
}
cache.notifyAll();
}