[java-gnome-hackers] The next stage in memory management
Brought to you by:
afcowie
From: Andrew C. <an...@op...> - 2010-01-08 06:30:56
|
Way back in the dark ages, we started the current version of java-gnome. We [especially Vreixo] invested a huge amount of time in getting the memory management correct, specifically the use of ToggleRefs to manage the reference count that a java-gnome proxy has on a GObject, while being able to return the existing proxy for a GObject if there is one, using WeakReferences and the JNI equivalent. Magic no end. Through extensive experience, that work has held up nicely. If you were to look in the base class Pointer, you'd see a nice little fragment I wrote four or so years ago as follows: /** * Parent release function. Will be called by the Java garbage collector * when it invokes the finalizer, so this is the time to release * references and free memory on the C side. */ protected abstract void release(); /* * This is a placeholder to remind us of the cleanup actions that will be * necessary, irrespective of the finalizer technique used. */ protected void finalize() { release(); } Right from the get-go, I knew that we'd have to have our own code path to free resources, and I also knew full well that Java's finalize() mechanism is "unreliable" and that really if you need to clean up after yourself you should be using PhantomReferences (or WeakReferences or SoftReferences, depending). Now, what most people meant when they talk about "unreliable" is that they are not "guaranteed" to be called; a number of circumstances [/implementations] just terminate the Java VM process without calling the finalizers of every bloody object. So if (say) you're holding on to database client connections, they won't necessarily get cleared / closed / etc. Bad. In normal usage, though, finalizers *do* indeed get called, and for our purposes they were fine. And so the placeholder above has been doing us. I've started to run into a circumstance where this is not ideal, however. I'm doing something that is [org.gnome.pango] Layout & LayoutLine heavy; down in Pango itself these use a lot of resources; ordinarily that's fine because they are transient, but the thing I am working on is generating a *lot* of them, and they aren't getting free()'d until ... well, last time I ran the app I got myself > 100 MB of writable memory before a full GC happened. Yeech. The problem is that the full Java garbage collector [and I'm talking about OpenJDK HotSpot here] does not ordinarily run until the VM thinks it is out of heap. And that isn't going to happen anytime soon on most systems. Which means that finalize() isn't get called until *MUCH* later than we'd like, and we're holding on to tons of memory (allocated by glib) unnecessarily. Telling people just to call System.gc() doesn't really seem to address the weakness. Which brings us back to the _other_ purpose of SoftReference, WeakReference, and PhantomReferences: taking actions on Java objects as they go through the lifecycle, including being able to do cleanup long before finalize() gets called by the GC in it's second last phase. See file:///usr/share/doc/openjdk-6-doc/api/java/lang/ref/package-summary.html#reachability for more details. Presumably we want another WeakReference, plus a ReferenceQueue. The question is: what will poll the reference queue, and when? Sometime people use a separate thread for that. Another possibility would be to use an idle handler setup from the native side. A third option would be to poll the reference queue as a (generated) part of every JNI call. Thoughts? AfC Sydney P.S. What I *really* want to do is override g_object_ref() and g_object_unref(), but that'd only be possible with a LD_PRELOAD hack. But if they were plugable, and in conjunction with setting the Glib allocator function [which is plugable] to use (say) direct buffers, we could really get cool about leak detection on both sides. But that's another project. -- Andrew Frederick Cowie Operational Dynamics is an operations and engineering consultancy focusing on IT strategy, organizational architecture, systems review, and effective procedures for change management: enabling successful deployment of mission critical information technology in enterprises, worldwide. http://www.operationaldynamics.com/ Sydney New York Toronto London |