This is an automated email from the ASF dual-hosted git repository.
wangweipeng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-fury.git
The following commit(s) were added to refs/heads/main by this push:
new 0437556e feat(java): avoid recompilation when gc happens for memory
pressure (#1411)
0437556e is described below
commit 0437556ef4f3445869923f6b90806f565fda0e33
Author: Shawn Yang <[email protected]>
AuthorDate: Sun Mar 17 18:47:34 2024 +0800
feat(java): avoid recompilation when gc happens for memory pressure (#1411)
---
.../java/org/apache/fury/builder/CodecUtils.java | 22 ++++++++--
.../org/apache/fury/codegen/CodeGenerator.java | 16 ++++----
.../org/apache/fury/resolver/ClassResolver.java | 16 ++++++++
.../main/java/org/apache/fury/util/DelayedRef.java | 48 ++++++++++++++++++++++
.../org/apache/fury/codegen/CodeGeneratorTest.java | 6 +--
5 files changed, 94 insertions(+), 14 deletions(-)
diff --git
a/java/fury-core/src/main/java/org/apache/fury/builder/CodecUtils.java
b/java/fury-core/src/main/java/org/apache/fury/builder/CodecUtils.java
index e5cd5a54..d13be51e 100644
--- a/java/fury-core/src/main/java/org/apache/fury/builder/CodecUtils.java
+++ b/java/fury-core/src/main/java/org/apache/fury/builder/CodecUtils.java
@@ -24,6 +24,7 @@ import java.util.Collections;
import org.apache.fury.Fury;
import org.apache.fury.codegen.CodeGenerator;
import org.apache.fury.codegen.CompileUnit;
+import org.apache.fury.resolver.ClassResolver;
import org.apache.fury.resolver.FieldResolver;
import org.apache.fury.serializer.Serializer;
import org.apache.fury.type.ClassDef;
@@ -81,14 +82,29 @@ public class CodecUtils {
if (beanClassClassLoader == null) {
beanClassClassLoader = fury.getClass().getClassLoader();
}
+ ClassResolver classResolver = fury.getClassResolver();
try {
// generated code imported fury classes.
beanClassClassLoader.loadClass(Fury.class.getName());
- codeGenerator =
CodeGenerator.getSharedCodeGenerator(beanClassClassLoader);
+ codeGenerator = classResolver.getCodeGenerator(beanClassClassLoader);
+ if (codeGenerator == null) {
+ codeGenerator =
CodeGenerator.getSharedCodeGenerator(beanClassClassLoader);
+ // Hold strong reference of {@link CodeGenerator}, so the referent of
`DelayedRef`
+ // won't be null.
+ classResolver.setCodeGenerator(beanClassClassLoader, codeGenerator);
+ }
} catch (ClassNotFoundException e) {
codeGenerator =
- CodeGenerator.getSharedCodeGenerator(
- beanClassClassLoader, fury.getClass().getClassLoader());
+ classResolver.getCodeGenerator(beanClassClassLoader,
fury.getClass().getClassLoader());
+ ClassLoader[] loaders = {beanClassClassLoader,
fury.getClass().getClassLoader()};
+ if (codeGenerator == null) {
+ codeGenerator =
+ CodeGenerator.getSharedCodeGenerator(
+ beanClassClassLoader, fury.getClass().getClassLoader());
+ // Hold strong reference of {@link CodeGenerator}, so the referent of
`DelayedRef`
+ // won't be null.
+ classResolver.setCodeGenerator(loaders, codeGenerator);
+ }
}
ClassLoader classLoader =
codeGenerator.compile(
diff --git
a/java/fury-core/src/main/java/org/apache/fury/codegen/CodeGenerator.java
b/java/fury-core/src/main/java/org/apache/fury/codegen/CodeGenerator.java
index c6be7358..da3bc7e0 100644
--- a/java/fury-core/src/main/java/org/apache/fury/codegen/CodeGenerator.java
+++ b/java/fury-core/src/main/java/org/apache/fury/codegen/CodeGenerator.java
@@ -23,7 +23,6 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -41,6 +40,7 @@ import org.apache.fury.collection.Collections;
import org.apache.fury.collection.MultiKeyWeakMap;
import org.apache.fury.util.ClassLoaderUtils;
import org.apache.fury.util.ClassLoaderUtils.ByteArrayClassLoader;
+import org.apache.fury.util.DelayedRef;
import org.apache.fury.util.GraalvmSupport;
import org.apache.fury.util.LoggerFactory;
import org.apache.fury.util.Preconditions;
@@ -71,9 +71,9 @@ public class CodeGenerator {
// FIXME The classloaders will only be reclaimed when the generated class
are not be referenced.
// FIXME CodeGenerator may reference to classloader, thus cause circular
reference, neither can
// be gc.
- private static final WeakHashMap<ClassLoader, SoftReference<CodeGenerator>>
sharedCodeGenerator =
+ private static final WeakHashMap<ClassLoader, DelayedRef<CodeGenerator>>
sharedCodeGenerator =
new WeakHashMap<>();
- private static final MultiKeyWeakMap<SoftReference<CodeGenerator>>
sharedCodeGenerator2 =
+ private static final MultiKeyWeakMap<DelayedRef<CodeGenerator>>
sharedCodeGenerator2 =
new MultiKeyWeakMap<>();
// use this package when bean class name starts with java.
@@ -301,11 +301,11 @@ public class CodeGenerator {
}
public static synchronized CodeGenerator
getSharedCodeGenerator(ClassLoader... classLoaders) {
- SoftReference<CodeGenerator> codeGeneratorWeakRef =
sharedCodeGenerator2.get(classLoaders);
+ DelayedRef<CodeGenerator> codeGeneratorWeakRef =
sharedCodeGenerator2.get(classLoaders);
CodeGenerator codeGenerator = codeGeneratorWeakRef != null ?
codeGeneratorWeakRef.get() : null;
if (codeGenerator == null) {
codeGenerator = new CodeGenerator(new
ClassLoaderUtils.ComposedClassLoader(classLoaders));
- sharedCodeGenerator2.put(classLoaders, new
SoftReference<>(codeGenerator));
+ sharedCodeGenerator2.put(classLoaders, new DelayedRef<>(codeGenerator));
}
return codeGenerator;
}
@@ -314,11 +314,11 @@ public class CodeGenerator {
if (classLoader == null) {
classLoader = CodeGenerator.class.getClassLoader();
}
- SoftReference<CodeGenerator> codeGeneratorWeakRef =
sharedCodeGenerator.get(classLoader);
- CodeGenerator codeGenerator = codeGeneratorWeakRef != null ?
codeGeneratorWeakRef.get() : null;
+ DelayedRef<CodeGenerator> ref = sharedCodeGenerator.get(classLoader);
+ CodeGenerator codeGenerator = ref != null ? ref.get() : null;
if (codeGenerator == null) {
codeGenerator = new CodeGenerator(classLoader);
- sharedCodeGenerator.put(classLoader, new SoftReference<>(codeGenerator));
+ sharedCodeGenerator.put(classLoader, new DelayedRef<>(codeGenerator));
}
return codeGenerator;
}
diff --git
a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
index e24e3f63..0e11568e 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
@@ -83,6 +83,7 @@ import org.apache.fury.annotation.Internal;
import org.apache.fury.builder.CodecUtils;
import org.apache.fury.builder.Generated;
import org.apache.fury.builder.JITContext;
+import org.apache.fury.codegen.CodeGenerator;
import org.apache.fury.codegen.Expression;
import org.apache.fury.codegen.Expression.Invoke;
import org.apache.fury.codegen.Expression.Literal;
@@ -245,6 +246,7 @@ public class ClassResolver {
descriptorsCache = new ConcurrentHashMap<>();
private ClassChecker classChecker = (classResolver, className) -> true;
private GenericType objectGenericType;
+ private Map<List<ClassLoader>, CodeGenerator> codeGeneratorMap = new
HashMap<>();
}
public ClassResolver(Fury fury) {
@@ -1796,6 +1798,20 @@ public class ClassResolver {
return enumStringResolver;
}
+ public CodeGenerator getCodeGenerator(ClassLoader... loaders) {
+ List<ClassLoader> loaderList = new ArrayList<>(loaders.length);
+ Collections.addAll(loaderList, loaders);
+ return extRegistry.codeGeneratorMap.get(loaderList);
+ }
+
+ public void setCodeGenerator(ClassLoader loader, CodeGenerator
codeGenerator) {
+ setCodeGenerator(new ClassLoader[] {loader}, codeGenerator);
+ }
+
+ public void setCodeGenerator(ClassLoader[] loaders, CodeGenerator
codeGenerator) {
+ extRegistry.codeGeneratorMap.put(Arrays.asList(loaders), codeGenerator);
+ }
+
public Fury getFury() {
return fury;
}
diff --git a/java/fury-core/src/main/java/org/apache/fury/util/DelayedRef.java
b/java/fury-core/src/main/java/org/apache/fury/util/DelayedRef.java
new file mode 100644
index 00000000..c2254ace
--- /dev/null
+++ b/java/fury-core/src/main/java/org/apache/fury/util/DelayedRef.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fury.util;
+
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+
+/**
+ * A weak reference which will have the longer lifetime of {@link
WeakReference} and {@link
+ * SoftReference}.
+ *
+ * @param <T> type of the referent.
+ */
+public class DelayedRef<T> {
+ // If referent is strong reachable, this won't be null.
+ private final WeakReference<T> weakRef;
+ // If other components doesn't strong hold the referent, this is used
+ // to cache and get the referent. But the reference will be set to null
+ // when there is a memory pressure.
+ private final SoftReference<T> softRef;
+
+ public DelayedRef(T o) {
+ weakRef = new WeakReference<>(o);
+ softRef = new SoftReference<>(o);
+ }
+
+ public T get() {
+ T t = weakRef.get();
+ return t != null ? t : softRef.get();
+ }
+}
diff --git
a/java/fury-core/src/test/java/org/apache/fury/codegen/CodeGeneratorTest.java
b/java/fury-core/src/test/java/org/apache/fury/codegen/CodeGeneratorTest.java
index 1f27527b..e184112e 100644
---
a/java/fury-core/src/test/java/org/apache/fury/codegen/CodeGeneratorTest.java
+++
b/java/fury-core/src/test/java/org/apache/fury/codegen/CodeGeneratorTest.java
@@ -23,7 +23,6 @@ import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
-import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
@@ -39,13 +38,14 @@ import org.apache.fury.collection.MultiKeyWeakMap;
import org.apache.fury.test.bean.Foo;
import org.apache.fury.util.ClassLoaderUtils;
import org.apache.fury.util.ClassLoaderUtils.ByteArrayClassLoader;
+import org.apache.fury.util.DelayedRef;
import org.testng.Assert;
import org.testng.annotations.Test;
@SuppressWarnings({"rawtypes", "unchecked"})
public class CodeGeneratorTest {
- private static WeakHashMap<ClassLoader, SoftReference<CodeGenerator>>
sharedCodeGenerator;
- private static MultiKeyWeakMap<SoftReference<CodeGenerator>>
sharedCodeGenerator2;
+ private static WeakHashMap<ClassLoader, DelayedRef<CodeGenerator>>
sharedCodeGenerator;
+ private static MultiKeyWeakMap<DelayedRef<CodeGenerator>>
sharedCodeGenerator2;
static {
try {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]