From: <zy...@us...> - 2010-09-08 06:27:21
|
Revision: 7112 http://jython.svn.sourceforge.net/jython/?rev=7112&view=rev Author: zyasoft Date: 2010-09-08 06:27:14 +0000 (Wed, 08 Sep 2010) Log Message: ----------- To address #1327 - removed use of Guava's FinalizableReferenceQueue and now does a passive cleanup of PySystemState-related data, so that classloaders will hopefully GC under a range of setups. Also de-registers the shutdown hook. Modified Paths: -------------- trunk/jython/Lib/test/test_jy_internals.py trunk/jython/Lib/test/test_weakref.py trunk/jython/src/org/python/core/Py.java trunk/jython/src/org/python/core/PySystemState.java trunk/jython/src/org/python/util/PythonInterpreter.java Modified: trunk/jython/Lib/test/test_jy_internals.py =================================================================== --- trunk/jython/Lib/test/test_jy_internals.py 2010-09-07 20:49:59 UTC (rev 7111) +++ trunk/jython/Lib/test/test_jy_internals.py 2010-09-08 06:27:14 UTC (rev 7112) @@ -50,7 +50,6 @@ Dog().bark() """) - pi.cleanup(); make_clean() # get to steady state first, then verify we don't create new proxies Modified: trunk/jython/Lib/test/test_weakref.py =================================================================== --- trunk/jython/Lib/test/test_weakref.py 2010-09-07 20:49:59 UTC (rev 7111) +++ trunk/jython/Lib/test/test_weakref.py 2010-09-08 06:27:14 UTC (rev 7112) @@ -12,8 +12,9 @@ def extra_collect(): """Kick Java's GC into gear""" gc.collect() - time.sleep(0.1) + time.sleep(0.2) gc.collect() + time.sleep(0.2) gc.collect() else: def extra_collect(): Modified: trunk/jython/src/org/python/core/Py.java =================================================================== --- trunk/jython/src/org/python/core/Py.java 2010-09-07 20:49:59 UTC (rev 7111) +++ trunk/jython/src/org/python/core/Py.java 2010-09-08 06:27:14 UTC (rev 7112) @@ -773,7 +773,7 @@ // memory error. Fix for bug #1654484 PyType.fromClass(OutOfMemoryError.class); } - public static PySystemState defaultSystemState; + public static volatile PySystemState defaultSystemState; // This is a hack to get initializations to work in proper order public static synchronized boolean initPython() { PySystemState.initialize(); Modified: trunk/jython/src/org/python/core/PySystemState.java =================================================================== --- trunk/jython/src/org/python/core/PySystemState.java 2010-09-07 20:49:59 UTC (rev 7111) +++ trunk/jython/src/org/python/core/PySystemState.java 2010-09-08 06:27:14 UTC (rev 7112) @@ -7,6 +7,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.net.URL; import java.net.URLDecoder; @@ -21,11 +23,11 @@ import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; +import java.util.concurrent.ConcurrentMap; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import com.google.common.base.FinalizablePhantomReference; -import com.google.common.base.FinalizableReferenceQueue; +import com.google.common.collect.MapMaker; import org.jruby.ext.posix.util.Platform; import org.python.Version; import org.python.core.adapter.ClassicPyObjectAdapter; @@ -153,9 +155,12 @@ // Automatically close resources associated with a PySystemState when they get GCed private final PySystemStateCloser closer; - private static final FinalizableReferenceQueue systemStateQueue = new FinalizableReferenceQueue(); + private static final ReferenceQueue systemStateQueue = new ReferenceQueue<PySystemState>(); + private static final ConcurrentMap<WeakReference<PySystemState>, PySystemStateCloser> sysClosers = Generic.concurrentMap(); +// static { +// startCleanupThread(); +// } - public PySystemState() { initialize(); closer = new PySystemStateCloser(this); @@ -1251,36 +1256,60 @@ return closer.unregisterCloser(resourceCloser); } - public void shutdown() { - closer.shutdown(); + public void cleanup() { + closer.cleanup(); } + private static void startCleanupThread() { + Thread cleanupThread = new Thread(new Runnable() { + public void run() { + while (true) { + try { + Reference<PySystemStateCloser> ref = systemStateQueue.remove(); + PySystemStateCloser closer = sysClosers.get(ref); + closer.cleanup(); + sysClosers.remove(ref); + } catch (InterruptedException ex) { + break; + } + } + } + }); + cleanupThread.setDaemon(true); + cleanupThread.start(); + } private static class PySystemStateCloser { private final ArrayList<WeakReference<ThreadState[]>> threadStateList = new ArrayList<WeakReference<ThreadState[]>>(); private final Set<Callable> resourceClosers = new LinkedHashSet<Callable>(); - private final FinalizablePhantomReference<PySystemState> sys; - private volatile boolean isShutdown = false; + private volatile boolean isCleanup = false; + private final Thread shutdownHook; private PySystemStateCloser(PySystemState sys) { - this.sys = new FinalizablePhantomReference<PySystemState>(sys, systemStateQueue) { - public void finalizeReferent() { - shutdown(); - } - }; - initShutdownCloser(); + shutdownHook = initShutdownCloser(); + WeakReference<PySystemState> ref = new WeakReference(sys, systemStateQueue); + sysClosers.put(ref, this); + cleanupOtherClosers(); } + private static void cleanupOtherClosers() { + Reference<PySystemStateCloser> ref; + while ((ref = systemStateQueue.poll()) != null) { + PySystemStateCloser closer = sysClosers.get(ref); + closer.cleanup(); + } + } + private synchronized void registerThreadState(ThreadState[] threadLocal, ThreadState ts) { - if (!isShutdown) { // is this really necessary? + if (!isCleanup) { threadLocal[0] = ts; threadStateList.add(new WeakReference<ThreadState[]>(threadLocal)); } } private synchronized void registerCloser(Callable closer) { - if (!isShutdown) { + if (!isCleanup) { resourceClosers.add(closer); } } @@ -1289,12 +1318,17 @@ return resourceClosers.remove(closer); } - private synchronized void shutdown() { - if (isShutdown) { + private synchronized void cleanup() { + if (isCleanup) { return; } - isShutdown = true; + isCleanup = true; + // close this thread so we can unload any associated classloaders in cycle with this instance + if (shutdownHook != null) { + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } + // clear out existing ThreadStates so that they can be GCed - this resolves ClassLoader issues for (WeakReference<ThreadState[]> ref : threadStateList) { ThreadState[] o = ref.get(); @@ -1308,18 +1342,21 @@ try { callable.call(); } catch (Exception e) { - // just continue + // just continue, nothing we can do } } resourceClosers.clear(); } - // Python scripts expect that files are closed upon an orderly shutdown of the VM. - private void initShutdownCloser() { + // Python scripts expect that files are closed upon an orderly cleanup of the VM. + private Thread initShutdownCloser() { try { - Runtime.getRuntime().addShutdownHook(new ShutdownCloser()); + Thread shutdownHook = new ShutdownCloser(); + Runtime.getRuntime().addShutdownHook(shutdownHook); + return shutdownHook; } catch (SecurityException se) { - Py.writeDebug("PySystemState", "Can't register shutdown closer hook"); + Py.writeDebug("PySystemState", "Can't register cleanup closer hook"); + return null; } } Modified: trunk/jython/src/org/python/util/PythonInterpreter.java =================================================================== --- trunk/jython/src/org/python/util/PythonInterpreter.java 2010-09-07 20:49:59 UTC (rev 7111) +++ trunk/jython/src/org/python/util/PythonInterpreter.java 2010-09-08 06:27:14 UTC (rev 7112) @@ -340,16 +340,18 @@ public void cleanup() { setSystemState(); - Py.getSystemState().callExitFunc(); + PySystemState sys = Py.getSystemState(); + sys.callExitFunc(); try { - Py.getSystemState().stdout.invoke("flush"); + sys.stdout.invoke("flush"); } catch (PyException pye) { // fall through } try { - Py.getSystemState().stderr.invoke("flush"); + sys.stderr.invoke("flush"); } catch (PyException pye) { // fall through } + sys.cleanup(); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |