Hi Jaroslav,
So ... activeReferenceQueue is a reference queue that embodies a thread
that does the polling and implements a psuedo-finalization mechanism.
This works fine in the normal case where the lifetime of the queue is
the lifetime of the "application". In the WAR case (and I don't know the
details of WAR deployment) each time it is deployed in the same VM we
get a new activeReferenceQueue and a new thread.
The basic issue is that the thread has a strong reference to the queue
and has no idea when it should exit and so the thread and queue remain
forever even if there is no user code with a reference to the queue -
does that sum it up?
Can the thread not hold a weakreference to the queue and poll using
remove(timeout) and then terminate when the queue reference is gone?
Thanks,
David
On 28/07/2014 11:06 PM, Jaroslav Tulach wrote:
Hello David,
thanks for being patient with me. I'll do my best to describe the
original context.
Dne Po 28. Ĩervence 2014 21:07:45, David Holmes napsal(a):
> I read the issue and still did not understand the nature of the problem.
> The netbeans bugs also did not shed any light on things for me. What is
> the functionality of the activeReferenceQueue
The functionality of the active reference queue is described in NetBeans
APIs[1]. I think the best way to describe it in context of existing JDK
APIs, is to call it "lightweight finalizer without classical finalizer
problems". To quote the Javadoc:
---
If you have a reference that needs cleanup, make it implement Runnable
and register it with the queue:
class MyReference extends WeakReference implements Runnable {
private final OtherInfo dataToCleanUp;
public MyReference(Thing ref, OtherInfo data) {
super(ref, Utilities.activeReferenceQueue());
dataToCleanUp = data;
}
public void run() {
dataToCleanUp.releaseOrWhateverYouNeed();
}
}
When the ref object is garbage collected, your run method will be
invoked by calling ((Runnable) reference).run()
--
The benefit taken from "finalizer" is that one does not need to start
own thread. The difference to "finalizer" is that the object is already
gone, e.g. no chance to re-activate it again.
We introduced the activeReferenceQueue API when we realized that many
modules over the code base start their own thread and try to do the
classical poll() cleanup. Once upon a time we used to have more than
twenty threads like this, and as overhead of a thread is not low, we
improved the NetBeans memory consumption quite a lot by introducing the
activeReferenceQueue.
> and what it is that there
> are problems with?
None in case of NetBeans. Once the activeReferenceQueue initializes
itself and its thread, it runs up until the termination of the system
and works great.
However NetBeans APIs can be used outside of NetBeans runtime container
and, when used in a WAR file, people started to get problems during
re-deploys.
Once we got a bug report[2] that it behaves poorly
when used inside of a WAR file. Whenever the WAR was redeployed, the number
of cleanup threads increased by one, which also caused major memory leaks.
Those problems could be fixed by using active polling as I wrote in
today's morning email:
> class Impl extends ReferenceQueue {}
> Reference<Impl> ref = new WeakReference<Impl>(new Impl());
>
> while (true) {
>
> Impl impl = ref.get();
> if (impl == null) {
>
> // no other Reference objects using the Impl queue.
> // exit this cleaner thread
> return;
>
> }
> Reference<?> ref = impl.remove(15000);
> if (ref == null) {
>
> impl = null; // don't hold strong ref to Impl queue
> System.gc(); // XXX: is anyone else holding reference to Impl queue?
> continue;
>
> }
> // do something with ref
>
> }
>
> this could work, althrough the problem is the XXX part.
>
> I need to release my own pointer to the Impl queue, tell the system
to try
> to garbage collect it. If it has not been removed, grap new strong
pointer
> to the Impl queue and wait again. I am not aware of any other way to ask
> for GC than System.gc, and having System.gc being called every 15s will
> likely decrease VM performance a bit.
>
> The proper solution (no reflection, no repeated polling) would in fact be
> simple: Being able to call:
>
> impl.remove();
>
> without anyone having strong reference to impl - e.g. without impl
being on
> stack during the remove call.
I don't know what else to add. So I wait for further question.
-jt
[1]
http://bits.netbeans.org/dev/javadoc/org-openide-util/org/openide/util/Utilities.html#activeReferenceQueue()
[2] https://netbeans.org/bugzilla/show_bug.cgi?id=206621