HuntExams Academy logo
JavaIntermediate#gc#memory

What is the purpose of the finalize() method and why is it discouraged?

Answer

finalize() was meant to run cleanup logic before an object is garbage collected, but it's unpredictable (no guaranteed timing), can hurt performance, and is deprecated since Java 9 in favor of try-with-resources and Cleaner.

Example

// Deprecated approach:
protected void finalize() { /* cleanup */ }
// Preferred: implement AutoCloseable and use try-with-resources

Detailed explanation

The finalize() method is a legacy cleanup hook declared in java.lang.Object. Its original purpose was to let an object release resources, such as native memory or operating-system handles, when garbage collection determined that it was no longer reachable through ordinary application references. It does not free the object's Java heap memory itself; the garbage collector manages that. Finalization is especially important to distinguish from resource management: an unreachable object may still hold a scarce external resource that needs prompt release.

With finalization enabled, an unreachable object that overrides finalize() may be scheduled for finalization rather than having its memory reclaimed immediately. The JVM invokes its finalizer through an unspecified execution mechanism, with no guarantee about timing or ordering. A finalizer might run much later, or not before the process exits. Finalization can also resurrect an object by storing a reference to it somewhere reachable, making reclamation more complicated. The JVM automatically invokes an object's finalizer at most once, even if that object becomes unreachable again after resurrection.

These behaviours make finalize() unsuitable for essential cleanup. Delayed cleanup can exhaust file descriptors or connections, while finalization adds processing overhead and can delay memory reclamation. Blocking finalizers can interfere with other finalization work, and uncaught exceptions from a finalizer are ignored rather than reported to the calling application. Finalization also creates security risks, including attacks involving partially constructed objects. Object.finalize() was deprecated in Java 9 and deprecated for removal in Java 18; candidates should not describe it as already removed merely because it is deprecated.

The preferred approach is explicit ownership: implement AutoCloseable and use try-with-resources so close() runs when control leaves the block, including when the body throws an exception. This provides predictable cleanup during normal execution, although abrupt JVM termination can still prevent it. Cleaner, introduced in Java 9, can provide a fallback for some native-resource cleanup, but it is also nondeterministic and is not a replacement for close(). Interviewers look for this distinction: garbage collection manages heap memory, whereas application code should release external resources predictably.

Key points to remember

  • finalize() was a legacy cleanup hook, not the mechanism that frees Java heap memory.
  • Finalizer execution has no guaranteed timing or ordering and may not occur before process exit.
  • Finalization can delay reclamation, add overhead, resurrect objects, and introduce security risks.
  • Object.finalize() was deprecated in Java 9 and deprecated for removal in Java 18.
  • Prefer AutoCloseable with try-with-resources; use Cleaner only as a nondeterministic fallback where appropriate.

Common mistakes candidates make

  • Assuming finalize() runs immediately when an object becomes unreachable or that System.gc() guarantees its execution.
  • Confusing finalize() with finally or believing it must release ordinary Java heap memory.
  • Presenting Cleaner as deterministic cleanup instead of explaining why explicit close() is preferred.

Likely follow-up questions

How are final, finally, and finalize() different?

final restricts reassignment, overriding, or inheritance depending on where it is used. finally is a block for cleanup when control exits a try statement, whereas finalize() is a deprecated object-lifecycle method associated with garbage collection.

What happens if both the try-with-resources body and close() throw exceptions?

The exception from the body remains the primary exception, while the exception from close() is recorded as a suppressed exception. You can inspect suppressed exceptions using Throwable.getSuppressed(); multiple resources are closed in reverse declaration order.

How does Cleaner differ from finalize()?

Cleaner registers a separate cleanup action and uses phantom reachability to trigger automatic cleanup without providing access to the referent for resurrection. The action must not retain the object being monitored, and automatic execution still has no guaranteed timing.

Interview tip: Start with finalize()'s original purpose, explain its lack of execution guarantees, and finish with AutoCloseable and try-with-resources as the preferred design.

Related Interview Questions

1
JavaIntermediate#serialization

What is serialization in Java?

Open
2
JavaIntermediate#serialization

What is the purpose of serialVersionUID?

Open
3
JavaIntermediate#serialization

What happens to static and transient fields during serialization?

Open