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.

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.

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.

JP

Reply via email to