groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jwagenleit...@apache.org
Subject groovy git commit: GROOVY-7683 - Memory leak when using Groovy as JSR-223 scripting language (closes #219)
Date Sun, 11 Sep 2016 03:07:33 GMT
Repository: groovy
Updated Branches:
  refs/heads/master 006b0ba12 -> a8fb77602


GROOVY-7683 - Memory leak when using Groovy as JSR-223 scripting language (closes #219)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/a8fb7760
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/a8fb7760
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/a8fb7760

Branch: refs/heads/master
Commit: a8fb776023253ebc2da35538f25eccd7d59997ed
Parents: 006b0ba
Author: John Wagenleitner <jwagenleitner@apache.org>
Authored: Sun Aug 28 12:04:24 2016 -0700
Committer: John Wagenleitner <jwagenleitner@apache.org>
Committed: Sat Sep 10 19:49:06 2016 -0700

----------------------------------------------------------------------
 .../codehaus/groovy/reflection/ClassInfo.java   | 84 ++++++++++----------
 .../reflection/GroovyClassValuePreJava7.java    | 10 +++
 2 files changed, 53 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/a8fb7760/src/main/org/codehaus/groovy/reflection/ClassInfo.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/reflection/ClassInfo.java b/src/main/org/codehaus/groovy/reflection/ClassInfo.java
index 2c0d8f4..faa5998 100644
--- a/src/main/org/codehaus/groovy/reflection/ClassInfo.java
+++ b/src/main/org/codehaus/groovy/reflection/ClassInfo.java
@@ -25,6 +25,7 @@ import org.codehaus.groovy.reflection.stdclasses.*;
 import org.codehaus.groovy.util.*;
 import org.codehaus.groovy.vmplugin.VMPluginFactory;
 
+import java.lang.ref.WeakReference;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.*;
@@ -32,16 +33,23 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Handle for all information we want to keep about the class
+ * <p>
+ * This class handles caching internally and its advisable to not store
+ * references directly to objects of this class.  The static factory method
+ * {@link ClassInfo#getClassInfo(Class)} should be used to retrieve an instance
+ * from the cache.  Internally the {@code Class} associated with a {@code ClassInfo}
+ * instance is kept as {@link WeakReference}, so it not safe to reference
+ * and instance without the Class being either strongly or softly reachable.
  *
  * @author Alex.Tkachman
  */
-public class ClassInfo {
+public class ClassInfo implements Finalizable {
 
     private final LazyCachedClassRef cachedClassRef;
     private final LazyClassLoaderRef artifactClassLoader;
     private final LockableObject lock = new LockableObject();
     public final int hash = -1;
-    private final Class klazz;
+    private final WeakReference<Class<?>> klazz;
 
     private final AtomicInteger version = new AtomicInteger();
 
@@ -68,11 +76,7 @@ public class ClassInfo {
     private static final GlobalClassSet globalClassSet = new GlobalClassSet();
 
     ClassInfo(Class klazz) {
-    	this.klazz = klazz;
-        if (ClassInfo.DebugRef.debug)
-          new DebugRef(klazz);
-        new ClassInfoCleanup(this);
-
+    	this.klazz = new WeakReference<Class<?>>(klazz);
         cachedClassRef = new LazyCachedClassRef(softBundle, this);
         artifactClassLoader = new LazyClassLoaderRef(softBundle, this);
     }
@@ -103,6 +107,19 @@ public class ClassInfo {
 	    }
     }
 
+    /**
+     * Returns the {@code Class} associated with this {@code ClassInfo}.
+     * <p>
+     * This method can return {@code null} if the {@code Class} is no longer reachable
+     * through any strong or soft references.  A non-null return value indicates that this
+     * {@code ClassInfo} is valid.
+     *
+     * @return the {@code Class} associated with this {@code ClassInfo}, else {@code null}
+     */
+    public final Class<?> getTheClass() {
+        return klazz.get();
+    }
+
     public CachedClass getCachedClass() {
         return cachedClassRef.get();
     }
@@ -222,7 +239,7 @@ public class ClassInfo {
             return answer;
         }
 
-        answer = mccHandle.create(klazz, metaClassRegistry);
+        answer = mccHandle.create(klazz.get(), metaClassRegistry);
         answer.initialize();
 
         if (GroovySystem.isKeepJavaMetaClasses()) {
@@ -248,6 +265,17 @@ public class ClassInfo {
         return (!enableGloballyOn || cachedAnswerIsEMC);
     }
 
+    /**
+     * Returns the {@code MetaClass} for the {@code Class} associated with this {@code ClassInfo}.
+     * If no {@code MetaClass} exists one will be created.
+     * <p>
+     * It is not safe to call this method without a {@code Class} associated with this {@code
ClassInfo}.
+     * It is advisable to aways retrieve a ClassInfo instance from the cache by using the
static
+     * factory method {@link ClassInfo#getClassInfo(Class)} to ensure the referenced Class
is
+     * strongly reachable.
+     *
+     * @return a {@code MetaClass} instance
+     */
     public final MetaClass getMetaClass() {
         MetaClass answer = getMetaClassForClass();
         if (answer != null) return answer;
@@ -375,7 +403,7 @@ public class ClassInfo {
         }
 
         public CachedClass initValue() {
-            return createCachedClass(info.klazz, info);
+            return createCachedClass(info.klazz.get(), info);
         }
     }
 
@@ -388,43 +416,17 @@ public class ClassInfo {
         }
 
         public ClassLoaderForClassArtifacts initValue() {
-            return new ClassLoaderForClassArtifacts(info.klazz);
+            return new ClassLoaderForClassArtifacts(info.klazz.get());
         }
     }
-    
-    private static class ClassInfoCleanup extends ManagedReference<ClassInfo> {
-
-        public ClassInfoCleanup(ClassInfo classInfo) {
-            super(weakBundle, classInfo);
-        }
 
-        public void finalizeRef() {
-        	ClassInfo classInfo = get();
-        	classInfo.setStrongMetaClass(null);
-        	classInfo.cachedClassRef.clear();
-        	classInfo.artifactClassLoader.clear();
-        }
+    @Override
+    public void finalizeReference() {
+        setStrongMetaClass(null);
+        cachedClassRef.clear();
+        artifactClassLoader.clear();
     }
 
-    private static class DebugRef extends ManagedReference<Class> {
-        public static final boolean debug = false;
-
-        private static final AtomicInteger count = new AtomicInteger();
-
-        final String name;
-
-        public DebugRef(Class klazz) {
-            super(softBundle, klazz);
-            name = klazz == null ? "<null>" : klazz.getName();
-            count.incrementAndGet();
-        }
-
-        public void finalizeRef() {
-            //System.out.println(name + " unloaded " + count.decrementAndGet() + " classes
kept");
-            super.finalizeReference();
-        }
-    }
-    
     private static class GlobalClassSet {
     	
     	private final ManagedLinkedList<ClassInfo> items = new ManagedLinkedList<ClassInfo>(weakBundle);

http://git-wip-us.apache.org/repos/asf/groovy/blob/a8fb7760/src/main/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java b/src/main/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
index e569a23..56ad0c1 100644
--- a/src/main/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
+++ b/src/main/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
@@ -18,6 +18,7 @@
  */
 package org.codehaus.groovy.reflection;
 
+import org.codehaus.groovy.util.Finalizable;
 import org.codehaus.groovy.util.ManagedConcurrentMap;
 import org.codehaus.groovy.util.ReferenceBundle;
 
@@ -40,6 +41,15 @@ class GroovyClassValuePreJava7<T> implements GroovyClassValue<T>
{
 		public void setValue(T value) {
 			if(value!=null) super.setValue(value);
 		}
+
+		@Override
+		public void finalizeReference() {
+			T value = getValue();
+			if (value instanceof Finalizable) {
+				((Finalizable) value).finalizeReference();
+			}
+			super.finalizeReference();
+		}
 	}
 
 	private class GroovyClassValuePreJava7Segment extends ManagedConcurrentMap.Segment<Class<?>,T>
{


Mime
View raw message