Make sure your methods work

What happens behind the scenes for finalize() method?

Ram Lakshmanan
© Shutterstock / PIYAWAT WONGOPASS

Why do we use finalize() method? And how do we make sure that it performs cleanup actions correctly? In this article, Ram Lakshmanan goes over how finalize() method works behind the scenes and to make sure it is properly implemented in your Java applications.

One Java question typically asked at interviews is “What is the purpose of finalize() method?”  While you can respond that the usual purpose of finalize() method is to perform cleanup actions before the object is discarded, there’s a lot more to it. Behind the scenes, the finalize() method needs to be handled in a special way. Otherwise, a small mistake in the finalize() method has the potential to jeopardize entire application’s availability. Let’s take a closer look.

Behind the scenes

While this seems pretty elementary, objects that have finalize() method are treated differently during the garbage collection process than the ones which don’t have it. During garbage collection phase, objects with finalize() method aren’t immediately evicted from the memory. Instead, those objects are added to an internal queue of java.lang.ref.Finalizer.

Across the whole JVM, there is only one low priority JVM thread by name ‘Finalizer’ that executes finalize() method of each object in the queue. Only after the execution of finalize() method does the object becomes eligible for Garbage Collection. If the application is producing a lot of objects which has finalize() method, the low priority “Finalizer” thread isn’t able to keep up with executing finalize() method. Then, significant amount unfinalized objects will start to build up in the internal queue of java.lang.ref.Finalizer, resulting in a significant amount of memory wastage.

Sometimes the “Finalizer” thread may start to WAIT or BLOCK while executing the finalize() method due to poor programming practices. If the “Finalizer” thread starts to wait or block, then the number of unfinalized objects in the internal queue of java.lang.ref.Finalizer will start to grow significantly. It eventually results in OutOfMemoryError, jeopardizing the availability of the JVM.

SEE ALSO: Java 10: These APIs are as good as gone


To illustrate this theory, we wrote a simple sample program.

public class SampleObject {

	public String data;
	public SampleObject(String data) { = data;
	public void finalize() {
		try {
			// Sleep for 1 minute.
			Thread.currentThread().sleep(1 * 60 * 1000);
		} catch (Exception e) {}
	public static void main(String[] args) {
		long counter = 0;
		while (true) {
			new SampleObject("my-fun-data-" + counter);
			System.out.println("created: " + counter++);

Basically, the main() method of this class continuously creates a SampleObject. Interestingly, part of this program is the finalize() method. This method puts the current executing thread (i.e. ‘Finalizer’ thread) to sleep for 1 minute. This example illustrates what happens during a poor implementation of the finalize() method.

When we ran the program above with a max heap size of 10 mb (i.e. -Xmx10M), it crashed a few seconds after launch with the java.lang.OutOfMemoryError error message.

This program crashed because SampleObject can be evicted from the memory after the execution of finalize() method. Since the ‘Finalizer’ thread is put to sleep, it couldn’t execute the finalize() method at the same rate in which main() method was creating new SampleObject. Thus, the memory was filled up and the program resulted in a java.lang.OutOfMemoryError error message.

On the other hand, when we commented out the finalize() method, the program ran continuously without experiencing any java.lang.OutOfMemoryError errors.

SEE ALSO: Begin your Java exploration: Advice and resources for Java beginners

How to diagnose this problem?

Your application might contain hundreds, thousands, or even millions of classes. It includes classes from third party libraries and frameworks. So, how will you identify poorly implementedfinalize() methods? This is where heap dump analysis tools like are handy to have.

When a heap dump was captured from the program above and uploaded to, it generated this useful report. The report has several sections, but the section that is of interest to us is “Objects waiting for finalization”.


Excerpt from the report generated by

This section of the report shows the amount of memory wasted due to objects waiting for finalization in your application. In this hypothetical example, the memory wasted is 7.66 MB (97.2%).


Objects waiting for finalization

When you click on the hyperlink given under ‘What are the objects waiting finalization?’, you will be able to see the objects waiting to be finalized. Basically, you will be able to see the object tree of j.l.r.ReferenceQueue (note: this is queue of the java.lang.ref.Finalizer object that holds reference of all objects whose finalize() method needs to be executed). If you go down the tree, it will show the objects that are sitting in the queue waiting to be finalized. Here, you can see two types of objects that are sitting in the queue:

  1. – occupying 56.8% of memory
  2. com.petals.finalize.SampleObject – occupying 11.5% of memory

BINGO!! These are the objects that is created in our sample program. So, utilizing a tool like HeapHero makes it easy to see where the finalize() method is poorly implemented.


Ram Lakshmanan

Every single day, millions & millions of people in North America—bank, travel, and commerce—use the applications that Ram Lakshmanan has architected. Ram is an acclaimed speaker in major conferences on scalability, availability, and performance topics. Recently, he has founded a startup, which specializes in troubleshooting performance problems.

Inline Feedbacks
View all comments