As for destiny of
https://bugs.openjdk.java.net/browse/JDK-8051843
- it depends whether we consider the one more signal thread overhead
important or not. I do. I would still like JDK9 to allow me to write
activeReferenceQueue with a single cleanup thread.
Or even more effective attempt: Maybe JDK could expose such queue by
itself. In such case we don't need much visible APIs and we can even
save one thread - as the call back the Runnables in existing Finalizer
one. Towards lightweight (and correct) finalization!
-jt
Dne Po 28. července 2014 19:04:25, Peter Levart napsal(a):
> Hello Jaroslav,
>
> Regardless of where it is implemented (in JDK or in NetBeans) it would
> be impossible to create something that doesn't do polling in a single
> thread and yet wait for two ReferenceQueues at the same time - one is
> the queue of Runnable references which you run() and the other is the
> queue of WeakReference(s) to the before-mentioned queue(s) (the ACTIVE
> in ActiveQueue). Each of these two queues has it's own 'lock' and there
> is no way to wait() for two locks at the same time in a single thread.
> But you could do this in two threads. I created an alternative
> implementation using two threads:
>
>
http://cr.openjdk.java.net/~plevart/misc/nb.ActiveQueue2/ActiveQueue2.java
>
> I deliberately commented-out the setDaemon(true) calls of both threads
> so it can be seen that JVM exits when both are finished in the little
> test at the end.
>
> It's easy to adapt this to use polling instead of 2nd thread. Just
> specify a time-out in a call to CleanupHandler.remove(timeout) and scrap
> the code for 2nd thread. The remaining thread will eventually find out
> that ReferenceQueue has been collected and will exit.
>
> Regards, Peter
>
> On 07/28/2014 03: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/Ut
> > ilities.html#activeReferenceQueue() [2]
> > https://netbeans.org/bugzilla/show_bug.cgi?id=206621