<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
  </head>
  <body style="background-color: rgb(255, 255, 255); color: rgb(0, 0,
    0);" bgcolor="#FFFFFF" text="#000000">
    Hi Jonathan,<br>
    <br>
    <div class="moz-cite-prefix">On 06/05/2015 11:11 PM, Jonathan Payne
      wrote:<br>
    </div>
    <blockquote
      cite="mid:0C527AE7-DED0-4731-9522-CECA3F618B9F@jpayne.net"
      type="cite"><!--[if !IE]><DIV style="border-left: 2px solid #009900; border-right: 2px solid #009900;  padding: 0px 15px; margin: 2px 0px;"><![endif]-->
      <pre wrap="">Hi.

I have had an interest in the topic of finalization ever since it caused me to abandon the G1 collector 3 or 4 years ago.

I’ve recently implemented a fix for my interpretation of the problem, which might be very different from the discussion currently ongoing in the thread entitled "JEP 132: More-prompt finalization”.

My problem was that finalization was not being run at all with the G1 collector. Not at all. That would have been fine with me because none of the existing objects in the Finalizer queue actually needed the service anymore: the files, sockets, streams, etc. had all been properly closed by my application, otherwise the server would have long since failed completely. However, those objects started to accumulate in the VM and eventually (8 hours later) brought the server down.</pre>
      <!--[if !IE]></DIV><![endif]--></blockquote>
    <br>
    The most probable cause of the described behavior might be that your
    finalizable objects live long enough so that they are promoted to
    the old-generation together with their tracking Finalizer(s)
    (FinalReferences). We know that a finalizable object must undergo at
    least 2 GC cycles to be reclaimed. The 1st cycle merely discovers
    the final-reachable objects and links their FinalReference(s) to the
    pending chain. ReferenceHandler thread then pushes them to the
    finalization queue where their final() methods are invoked by
    finalizer thread which also clears their associated
    FinalReference(s) and unlinks them from the double-linked list.
    During the 2nd cycle, such finalizable objects are usually found
    unreachable and are reclaimed. It might be that G1 has (or had) a
    performance problem so that it couldn't discover final-reachable
    objects in old-generation soon enough to push them through 2 cycles
    before the system choked.<br>
    <br>
    This is roughly similar to a problem you might have if lots of
    normal objects get promoted to old-generation, but it might be the
    effects are more drastic in G1 when those objects are finalizable.
    So you might be able to tune your app by increasing the young
    generation and/or the time it takes before objects are promoted to
    old-generation.<br>
    <br>
    I understand that it would be desirable for a finalizable object to
    be made "untracked" as soon as it is manually cleaned-up. This would
    most certainly give a relief to GC as it could reclaim such
    untracked objects immediately like normal objects without pushing
    them through all the finalization steps.<br>
    <br>
    Such feature would need new API. Here's my take on such API
    incorporated in my prototype. This feature is mostly independent of
    other changes in the prototype and could be provided stand-alone. I
    choose to incorporate it into the prototype to compare it's overhead
    with classical finalization in unchanged and changed JDKs:<br>
    <br>
       
<a class="moz-txt-link-freetext" href="http://cr.openjdk.java.net/~plevart/misc/JEP132/ReferenceHandling/webrev.03/">http://cr.openjdk.java.net/~plevart/misc/JEP132/ReferenceHandling/webrev.03/</a><br>
    <br>
    The java.lang.ref.Finalizator is a public subclass of
    package-private Finalizer which is a subclass of package-private
    FinalReference which is a subclass of public Reference. The public
    API therefore consists just of two types: Reference and Finalizator
    and the public methods either implemented or inherited by
    Finalizator. Finalizator is basically just a special kind of
    Reference, which can't be subclassed (is final), can't be
    registeread with a custom reference-queue, and can only be
    constructed using a Finalizator.create(finalizee, thunk) factory
    method taking a 'finalizee' to be tracked and a 'thunk' that is
    usually just an adapter for invoking a private cleanup method on the
    finalizee. Finalizator also implements java.lang.Runnable. It's
    run() method is invoked by finalization infrastructure or manually
    by user code that wishes to promptly trigger clean-up (from
    AutoCloseable.close() method for example).<br>
    <br>
    Here's how a classical finalizable class that also implements
    AutoCloseable might be implemented. Note that the class must
    implement it's own logic to make clean-up idempotent, since
    finalize() will be called even after close() has manually or
    automatically already been called:<br>
    <br>
        static final class Finalizable extends AtomicBoolean implements
    AutoCloseable {<br>
    <br>
            @Override<br>
            protected void finalize() throws Throwable {<br>
                close();<br>
            }<br>
    <br>
            @Override<br>
            public void close() {<br>
                // close must be idempotent<br>
                if (compareAndSet(false, true)) {<br>
                    // clean-up invoked at most once<br>
                }<br>
            }<br>
        }<br>
    <br>
    <br>
    And here's how an alternative celanup might be implemented using
    Finalizator. Finalizator already guarantees that it's 'thunk' will
    be called at most once regardless of whether it was triggered by GC
    and/or manually:<br>
    <br>
    <br>
        static final class Destroyable implements AutoCloseable {<br>
            final Finalizator<Destroyable> finalizator =<br>
                Finalizator.create(this, Destroyable::destroy);<br>
    <br>
            void destroy() {<br>
                // clean-up invoked at most once<br>
            }<br>
    <br>
            @Override<br>
            public void close() {<br>
                // close just runs the finalizator<br>
                finalizator.run();<br>
            }<br>
        }<br>
    <br>
    <br>
    As soon as Finalizator is run() 1st time, it is cleared and unlinked
    from the doubly-linked list. After that, GC can reclaim it and the
    finalizee right away without pushing them through the discovery and
    reference processing pipeline only to unlink the Finalizer from the
    doubly-linked list.<br>
    <br>
    I have done some testing and the results of creating and destroying
    100M objects with a sustained rate of ~90 objects/ms with or without
    performing (AutoCloseable) clean-up immediately after construction
    gives the following results:<br>
    <br>
    <br>
    Finalization, ORIGINAL<br>
    <br>
    real    2m5.958s<br>
    user    0m33.855s<br>
    sys     0m1.982s<br>
    <br>
    <br>
    AutoCloseable combined with Finalization, ORIGINAL<br>
    <br>
    real    2m0.952s<br>
    user    0m32.103s<br>
    sys     0m1.730s<br>
    <br>
    <br>
    Finalization, PATCHED<br>
    <br>
    real    2m0.519s<br>
    user    0m16.664s<br>
    sys     0m1.240s<br>
    <br>
    <br>
    AutoCloseable combined with Finalization, PATCHED<br>
    <br>
    real    1m55.641s<br>
    user    0m16.872s<br>
    sys     0m1.218s<br>
    <br>
    <br>
    Finalizator-based cleanup, PATCHED<br>
    <br>
    real    2m1.379s<br>
    user    0m17.422s<br>
    sys     0m1.321s<br>
    <br>
    <br>
    AutoCloseable combined with Finalizator-based cleanup, PATCHED<br>
    <br>
    real    1m55.169s<br>
    user    0m4.167s<br>
    sys     0m1.139s<br>
    <br>
    <br>
    <br>
    We see what I have already shown before that my prototype
    practically halves the CPU overhead of finalization infrastructure.
    Just making an object AutoCloseable and promptly doing the clean-up
    can not reduce this overhead if the object is also finalizable. But
    if manual clean-up also "unregisters" the Finalizator from the
    doubly-linked list and clears it, it spares the finalization
    infrastructure from processing it as a finalizable object which
    further reduces the CPU overhead for a factor of 4, totaling just
    1/8th of overhead of classic finalization with current JDK. Besides
    greatly reduced CPU overhead, such objects are also potentially more
    promptly reclaimed by GC, freeing memory for other more useful
    things...<br>
    <br>
    <br>
    <blockquote
      cite="mid:0C527AE7-DED0-4731-9522-CECA3F618B9F@jpayne.net"
      type="cite"><!--[if !IE]><DIV style="border-left: 2px solid #009900; border-right: 2px solid #009900;  padding: 0px 15px; margin: 2px 0px;"><![endif]-->
      <pre wrap="">
Which brings me to a few points:

Finalization as conceived in the early JDKs was a bad idea. To make matters worse, the way we then made use of it in those early days was A REALLY REALLY bad idea.
None of this mattered in those days because the GC ran often and quickly and finalization occurred during every GC cycle.
There may be situations where finalization as a feature actually matters, but in the intervening years the JDK has added new technologies that provide a way to accomplish finalization on your own, in your own code. A few helper classes and it might even be easy when it’s necessary, which is hopefully almost never.
Many of the uses of finalize() in the JDK today are bad and should be deleted.

My fix, BTW, was to use a back door (that I added to SharedSecrets) in all the JDK classes that had a finalize() method, so that when a resource is properly closed, by calling the close() method for example, the back door would remove the Finalizer for the specified object from the linked list of Finalizer objects, thus removing it from the finalization equation altogether. I implemented this, and then the various tests of creating a huge number of objects with a finalize() method ran quickly and flawlessly with no horrific GCs or even a growing memory pool. The main problem with my solution was that there was this nasty SharedSecrets back door, so it has been rejected and probably rightly so.

However, it proved a point.

But now I am wondering why the actual right thing to do is not simply this:

        Remove the finalize() method from all the worst offenders in the JDK.

I cannot remember all the places I patched when I implemented my fix, but the majority of them were pieces of code that absolutely had a close() method. If you don’t close objects when you’re done with them, your program PROBABLY SHOULD BE BROKEN. But even if you do not accept that, for all practical purposes, the program IS broken today because finalization is absolutely NOT run in a timely enough fashion.</pre>
      <!--[if !IE]></DIV><![endif]--></blockquote>
    <br>
    I have shown that we can have a cake and eat it too. Combining
    Finalizator-based clean-up with manual (or AutoCloseable) clean-up
    is a win-win situation. Programs that forget to call close() still
    work and those that do prompt close()ing will not be affected by
    finalization overhead. The migration of internal JDK code from
    finalize() methods to Finalizator-based cleanup should be simple and
    straight-forward.<br>
    <br>
    So what are we waiting for? ;-)<br>
    <br>
    <blockquote
      cite="mid:0C527AE7-DED0-4731-9522-CECA3F618B9F@jpayne.net"
      type="cite"><!--[if !IE]><DIV style="border-left: 2px solid #009900; border-right: 2px solid #009900;  padding: 0px 15px; margin: 2px 0px;"><![endif]-->
      <pre wrap="">
BTW - I never understood why CMS and other GC’s had absolutely no problem running finalization in a very timely fashion while the G1 collector just never seemed to get around to it. My interpretation of that fact has always led me to believe that it’s not a throughput issue with the finalization thread (not in real world examples, anyway) but rather a GC implementation that didn’t feel the need to be thorough enough to make sure something is ready to be finalized. I mean, when the G1 collector was forced to run a full collection (a death sentence on a 15Gb heap but it did occur) all the finalizable objects were found AND finalized immediately, all 15 or 20 million of them.

So in summary:

(1) The problem with finalization is that people use it. And more importantly, that the JDK is filled with inappropriate uses of it.

(2) The main solution is probably just to delete the inappropriate uses in the JDK. But if that’s not OK, then some sort of patch like what I did which allows the JDK classes to unregister the Finalizer’s when they are no longer needed, i.e., when the object knows that it has cleaned itself up.

I am curious to hear your thoughts.</pre>
      <!--[if !IE]></DIV><![endif]--></blockquote>
    <br>
    Thanks for the description of the problem you have with
    finalization. JDK has an internal alternative to finalization called
    sun.misc.Cleaner, which has basically the same API and
    implementation as my presented Finalizator with the following
    differences:<br>
    <br>
    - Cleaner is a PhantomReference which means that the referent is not
    obtainable any more when it is triggered, so clean-up code can only
    work on state that is not part of the referent (captured by
    Cleaner's thunk at the time of construction). This is suitable
    sometimes but not always.<br>
    - Cleaner(s) are executed by the ReferenceHandler thread direclty
    which makes them unsuitable for public consumption as their thunk's
    must guarantee to be executed quickly or else the whole reference
    processing infrastructure blocks. Finalizator(s) are executed by the
    same thread(s) as Finalizer(s).<br>
    <br>
    While it would be possible to retro-fit internal JDK classes to use
    Cleaner(s) instead of finalize() methods, this would require more
    refactoring which is always tricky. Finalizators, on the other hand,
    could be used as a drop-in replacement for finalize() method.<br>
     <br>
    <blockquote
      cite="mid:0C527AE7-DED0-4731-9522-CECA3F618B9F@jpayne.net"
      type="cite"><!--[if !IE]><DIV style="border-left: 2px solid #009900; border-right: 2px solid #009900;  padding: 0px 15px; margin: 2px 0px;"><![endif]-->
      <pre wrap="">
JP

</pre>
      <!--[if !IE]></DIV><![endif]--></blockquote>
    <br>
    Regards, Peter<br>
    <br>
  </body>
</html>