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; > >>