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