This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.0 by this push:
new 8e5eac1 fix cache Class avoid PermGen space OOM in dubbo3.0 (#7386)
8e5eac1 is described below
commit 8e5eac1acff7fa987dd3a2b4dfaaa5137b673f1d
Author: xiaoheng1 <[email protected]>
AuthorDate: Tue Apr 13 14:31:56 2021 +0800
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
---
.../org/apache/dubbo/common/bytecode/Proxy.java | 53 ++++++++++++++++++----
1 file changed, 43 insertions(+), 10 deletions(-)
diff --git
a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
index bb2b40b..c7fc5b2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
@@ -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();
}