Overhead of a new thread was: Benefits of activeReferenceQueue

Jaroslav Tulach jaroslav.tulach at oracle.com
Tue Jul 29 08:18:29 UTC 2014


Thanks Peter,
I had a feeling that two threads might address the issue and your work indicates they 
really can. I am sort of worried about the overhead of a single thread (~1MB?), but 
certainly using two threads is better than having our current reflection which works on 
JDK7, JDK8, but is broken on JDK9. I see you in the list of approved OCAs: 
http://www.oracle.com/technetwork/community/oca-486395.html#l[1] 
and as such I think I can copy your sample and use it to improve NetBeans. You will 
have been able to consider yourself a NetBeans contributor when NetBeans 8.0.1 is 
out. Thanks.

As for destiny of 
https://bugs.openjdk.java.net/browse/JDK-8051843[2] 
- 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;
> >>    


More information about the core-libs-dev mailing list