When to use finalizers and garbage collection in Java?

Asked

Viewed 1,132 times

18

When to use the methods System.gc() and finalize()? I read that it is very useful in object orientation to destroy memory objects that are not being referenced and to finish tasks, but I see few programmers using. Example used, taken from the Java book Programmer’s Guide 2nd edition.

package OrientacaoObjetos;

public class Objeto {
     private static int instancias = 0;
     private int id;

     public Objeto() {
         id = instancias++;
         System.out.println("Objeto.Objeto() [id=" + id + "]");
     }

     public static int getInstancias() { return instancias; }

     public int getId() { return id; }

     @Override
     public void finalize() {
         instancias--;
         System.out.println("Objeto.finalize() [id=" + id+ "]");
     }
}
package OrientacaoObjetos;

public class TesteGC {
    public static void main(String[] args) {
        System.out.println("Instancias = " + Objeto.getInstancias());
        for (int i = 0; i < 10; i++) {
            Objeto o = new Objeto();
        }
        System.out.println("Instancias = " + Objeto.getInstancias());
        System.gc();
        System.out.println("Instancias = " + Objeto.getInstancias());
    }
}

3 answers

18


The method finalize() is one of the most hated things in Java.

The general recommendation is never to use it!

In general, try to do resource cleaning on the finalize() is not good practice because:

  • Often, the finalize() is overwritten to do unnecessary cleaning, such as setting references to objects to null. The garbage collector is already smart enough to do it alone without needing help.

  • Code using the finalize() is much slower. The presence of the method finalize() forces JVM to do extra work and inhibits a lot of optimizations, as well as greatly complicating memory management in Java.

  • The method finalize() can resurrect dead objects, including objects for which the method finalize() has been called before.

  • Implementation of the method finalize() is neither guaranteed nor predictable. It is even possible that the JVM never invokes them. Or summon them long after the object in question has died.

  • The method finalize() encourages bad programming practice, that the object can do its own cleaning instead of the programmer doing it. Almost always the garbage collector knows how to do the proper cleaning itself. In the most complex cases, it is recommended to use a block Try-Finally or Try-with-Resources.

  • The method finalize() is executed in a thread managed by the garbage collector. If implemented improperly, this can result in degradation of waste collector performance, or even in a deadlock or other problems with threads interfering with the garbage collector, which is something very serious.

  • As ReferenceQueues of java are a much cleaner alternative than using the method finalize(). See more about this here.

Anyway, it’s really hard to find a situation where the finalize() justified. I have seen only two situations to date where he is justified:

  • When the object in question contains references to buffers or objects that are outside the JVM, they are implemented natively through JNI. In this case, the finalize() is something that serves to avoid memory-Leaks and memory corruption.

  • To give a message like System.out.println("Erro: O objeto XPTO não foi finalizado adequadamente");, but even then this would only be for objects that really need something very special to be closed and yet this practice is questionable.

As to the System.gc(), the garbage collector usually does a great job to decide when is a good time to run without needing your help, and therefore you should not need the System.gc(). The System.gc() is just a suggestion, and the JVM can completely ignore it if you prefer. Also, the use of System.gc() can cause serious performance bottlenecks when making the garbage collector perform at inappropriate times or redundantly. And almost always when the System.gc() is used, the person who put it there does not understand right what is doing.

Starting from Java 9, the method finalize() was rendered obsolete (@Deprecated). Here is what was added in the Javadoc:

The finalization Mechanism is inherently problematic. Finalization can lead to performance issues, deadlocks, and hangs. Errors in finalizers can lead to Resource Leaks; there is no way to Cancel finalization if it is no longer necessary; and no Ordering is specified Among calls to finalize methods of Different Objects. Furthermore, there are no guarantees regarding the timing of finalization. The finalize method Might be called on a finalizable Object only after an indefinite delay, if at all. Classes Whose instances hold non-heap Resources should provide a method to enable Explicit release of those Resources, and they should also implement AutoCloseable if appropriate. The Cleaner and PhantomReference provide more Flexible and Efficient Ways to release Resources when an Object Becomes unreachable.

Translating into Portuguese:

The shutdown mechanism is inherently problematic. Shutdown can lead to performance issues, deadlocks, and crashes. Errors in finalizers can cause resource leaks; there is no way to cancel a completion if it is no longer needed; and no sorting is specified between method calls finalize of different objects. Also, there is no guarantee as to when the completion will take place. The method finalize can be called on a finalizable object only after an indefinite waiting time, if it is indeed called. Classes in which instances keep references to resources outside the heap should provide a method to explicitly release such resources, and they should also implement AutoCloseable if appropriate. The Cleaner and the PhantomReference provide more flexible and efficient means of releasing resources when an object becomes unattainable.

See in particular these links:

10

They don’t use it because it’s not meant to be. There must be a strong reason to use them directly in production application code and there is rarely this strong reason.

In general the System.gc is used in test codes or require extreme optimization (even these I have my doubts), this is nothing common.

Calling him causes trouble. I will not go into detail but separate memory in generations should avoid collecting as much as possible and this method forces its execution, almost always without bringing any kind of gain, on the contrary.

If you use it and it is not a performance, you are doing something wrong. And if you do not master its use, even in this situation, you are doing something wrong. There’s a lot of myth about this.

The finalize must be invoked by the garbage collector and not to be called individually. At least not under normal conditions. Only very specific cases, probably only at the time of testing something can be called manually. Relying on it being manually invoked for your application to work is a huge mistake.

Note that this method may never be called, even by the garbage collector.

For both there is enough reliable literature saying not to use them. A documentation, the book Effective Java and the question in the OS are examples.

So you don’t see the programmers using or because they know they shouldn’t use or because they don’t know anything about it and luckily they stay away from it, which is quite appropriate.

After editing and placing the book code it is noted that the example is just a test or demonstration. It’s not a real production code, so it’s coherent.

  • The book is Java Programmer’s Guide 2edit.

  • 1

    You have quoted in your question the passage that says this. I will exorcise the book :D

  • @bigown, has experienced memory management problems?

  • @Wellingtonavelino depends on which, I’ve been through several, but each has its own peculiarity.

  • @bigown, example: 100% CPU on server or outOfMemory

  • 1

    @Wellingtonavelino 100% CPU is no memory management problem. I’ve had outOfMemory but not in Java. I’ve never programmed in real Java :D

  • hahaha, got it! @bigown

Show 2 more comments

6

I would like to add about the finalize and its interaction with GC (garbage collector):

  1. They are executed from asynchronous form to the Garbage Collector thread, that other one is a Daemon Thread of pending, low-priority finalizers. It is a common misconception that a major or minor Collection makes the GC thread wait for the execution of each finalizer of the collected instances.
  2. There is no esotericism because there is no guarantee as to the execution of the finishers. This is because Daemon Threads, as the Finalizer System Thread of the JVM do not prevent (secure) the completion of the JVM process, that is, when the main thread (of Main Thread Group) ends, she interrupts all system threads and consequently the implementation of finalize who are in line.
  3. As I explained earlier, GC does not execute finaliters, only adds them in low priority execution queue (pending finalisers). Therefore he doesn’t dislodge his memory at that moment. This can be critical to the garbage collection process and consequently to the application if the execution of the finalizers takes time, since this would be a classic case of memory Leak.
  4. You can also suggest the JVM that she prioritize the execution of the pending finaliser methods, using Runtime.getRuntime().runFinalization() or System.runFinalization().
  5. There is a method System.runFinalizersOnExit(true) which can be used to force the JVM process to wait for the execution of all finalize before its completion. This method is discontinued and is unsafe. Citing the class documentation:

    This method is inherently unsafe. It may result in finalizers being called on live Objects while other threads are concurrently manipulating those Objects, Resulting in erratic behavior or deadlock.

    What translating into Portuguese is:

    This method is inherently unsafe. It can result in finishers being called on living objects while other threads are concurrently manipulating these objects, resulting in erratic or deadlock behavior.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.