28

(This question is different from Why would you ever implement finalize()? This question is about deprecation from the Java platform, and the other question is about whether one should use this mechanism in applications.)

Why is the finalize() method deprecated in Java 9?

Yes it could be used in wrong way (like save an object from garbage collecting [only one time though] or try to close some native resources within it [it's better than don't close at all though]) as well as many other methods could be used wrongly.

So is finalize() really so dangerous or absolutely useless that it's necessary to kick it out of Java?

Stuart Marks
  • 120,620
  • 35
  • 192
  • 252
J.J. Beam
  • 2,054
  • 1
  • 15
  • 33
  • 4
    See also the discussions linked from the OpenJDK bug: https://bugs.openjdk.java.net/browse/JDK-8165641 – Daniel Pryden May 14 '19 at 23:15
  • 3
    Short answer, though: Yes. It is useless far more often than people think, dangerous to use even for experts who understand it very well (for example, unless you know what a reachability fence is and how to use one, I guarantee that your finalizers that manage native resources are all buggy), and it's an attractive nuisance for people who are looking for C++-style destructors. I say: farewell to finalizers, and good riddance. – Daniel Pryden May 14 '19 at 23:19
  • 2
    Your *question* may be different, but the *answer* is the same. (That's why the message is phrased as "This question already has an answer here.") If there is no valid use case, then deprecation is natural. – Daniel Pryden May 14 '19 at 23:44
  • Here is a thread about what you should replace it with: https://stackoverflow.com/questions/47762986/replacing-finalize-in-java – Thilo May 14 '19 at 23:58
  • While @DanielPryden has already explained why it doesn't really matter that your question is different from the duplicate, I'd also add that your question is probably off topic for Stack Overflow since it is not really about a programming issue, and any answers would be _"primarily opinion-based"_. (I suppose you could have been incredibly lucky and received an answer from the person who was responsible for deciding to deprecate `finalize()` in JDK 10 but it's pretty unlikely, and any answer from anyone else would have been mere speculation.) – skomisa May 15 '19 at 03:38
  • 3
    @skomisa Too bad this question was closed. There is a set of questions about the *rationale* for decisions that certainly can be answered. Either people involved in the decision might show up and answer it -- which has certainly happened before, particularly in regard to recent decisions -- or the answer might be written down somewhere, either in a mailing list post or a comment in a bug report. Rationale may be subjective, but it can be definitive and not purely opinion-based. – Stuart Marks Jun 04 '19 at 16:09
  • 6
    @DanielPryden You don't know that the answer is the same, unless you were involved in the decision. I was; I don't think you were. – Stuart Marks Jun 04 '19 at 16:10
  • @StuartMarks: You are of course correct. The only knowledge I have of the rationale is what is publicly available in the mailing list archives. If you feel that the question can be meaningfully answered without just devolving into a re-hash of why finalizers are problematic, I have no objection. I will refrain from any further actions on this question; please vote to re-open if you wish. I will admit that part of my eagerness to dupe-close the question is the somewhat rant-y nature of the phrasing ("So is finalize() method really so dangerous or absolutely useless to kick it out from Java?"). – Daniel Pryden Jun 04 '19 at 17:02
  • @StuartMarks: For what it's worth, since you hold a gold badge in the `java` tag, you can single-handedly reopen the question if you believe it should be open. – Daniel Pryden Jun 04 '19 at 17:03
  • 1
    @DanielPryden Thanks for your responses. The un-dupe-hammer works! I didn't know that. I knew about the dupe-hammer but I seem to recall having to vote and wait for other votes to reopen closed questions in the past. In any case I'll provide an answer at some point. – Stuart Marks Jun 05 '19 at 03:05
  • @StuartMarks Well I certainly take your (implied) point that since you were involved in the decision to deprecate `Object.finalize()`, it may make sense to reopen this, as suggested in another comment. I guess `Object.finalize()` may have been deprecated specifically in Java 9 (as opposed to any earlier/later release) because of the the addition of the `Cleaner` class in Java 9, and [JDK-8165641 Deprecate Object.finalize](https://bugs.openjdk.java.net/browse/JDK-8165641) somewhat supports that view, but that's just pure speculation on my part. Anyway, voting to reopen based on your comments. – skomisa Jun 05 '19 at 03:15
  • @StuartMarks Heh - I see the question was reopened while I was writing my comment. – skomisa Jun 05 '19 at 03:16
  • 1
    @skomisa Yep, Daniel Pryden pointed out to me that I could do it myself, so I did! In any case, thanks for your response. I think there is more to be said that's not in the other answer. Sorry I was a bit snippy about this -- I do think that questions about rationale are different from pure "opinion-based" questions that are things like "Is X better than Y?" and that it's possible to have useful (though subjective) answers about rationale. – Stuart Marks Jun 05 '19 at 03:27
  • @StuartMarks [1] I agree with all that, and with hindsight I was obviously hasty in suggesting that it was unlikely for anyone involved in the decision to deprecate `finalize()` to respond here - my bad. [2] Though not a duplicate, [Should Java 9 Cleaner be preferred to finalization?](https://stackoverflow.com/q/52879761/2985643) seems relevant. – skomisa Jun 05 '19 at 03:40
  • 1
    @skomisa (Ah, it's closed-opinion-based where I've had to wait for reopen votes, whereas this one was reopened immediately because it was closed as a duplicate. I had mixed those up.) In any case maybe I reopened too quickly, because this question now seems to be attracting poor answers! – Stuart Marks Jun 05 '19 at 03:48

1 Answers1

36

Although the question was asking about the Object.finalize method, the subject really is about the finalization mechanism as a whole. This mechanism includes not only the surface API Object.finalize, but it also includes specifications of the programming language about the life cycle of objects, and practical impact on garbage collector implementations in JVMs.

Much has been written about why finalization is difficult to use from the application's point of view. See the questions Why would you ever implement finalize()? and Should Java 9 Cleaner be preferred to finalization? and their answers. See also Effective Java, 3rd edition by Joshua Bloch, Item 8.

Briefly, some points about the problems associated with using finalizers are:

  • they are notoriously difficult to program correctly

  • in particular, they can be run unexpectedly when an object becomes unreachable unexpectedly (but correctly); for example, see my answer to this question

  • finalization can easily break subclass/superclass relationships

  • there is no ordering among finalizers

  • a given object's finalize method is invoked at most once by the JVM, even if that object is "resurrected"

  • there are no guarantees about timeliness of finalization or even that it will run at all

  • there is no explicit registration or deregistration mechanism

The above are difficulties with the use of finalization. Anyone who is considering using finalization should reconsider, given the above list of issues. But are these issues sufficient to deprecate finalization in the Java platform? There are several additional reasons explained in the sections below.

Finalization Potentially Makes Systems Fragile

Even if you write an object that uses finalization correctly, it can cause problems when your object is integrated into a larger system. Even if you don't use finalization at all, being integrated into a larger system, some parts of which use finalization, can result in problems. The general issue is that worker threads that create garbage need to be in balance with the garbage collector. If the garbage collector falls behind, at least some collectors can "stop the world" and do a full collection to catch up. Finalization complicates this interaction. Even if the garbage collector is keeping up with application threads, finalization can introduce bottlenecks and slow down the system, or it can cause delays in freeing resources that result in exhaustion of those resources. This is a systems problem. Even if the actual code that uses finalization is correct, problems can still occur in correctly programmed systems.

(Edit 2021-09-16: this question describes a problem where a system works fine under low load but fails under high load, likely because the relative rate of allocation outstrips the rate of finalization under high load.)

Finalization Contributes to Security Issues

The SEI CERT Oracle Coding Standard for Java has a rule MET12-J: Do not use finalizers. (Note, this is a site about secure coding.) In particular, it says

Improper use of finalizers can result in resurrection of garbage-collection-ready objects and result in denial-of-service vulnerabilities.

Oracle's Secure Coding Guidelines for Java SE is more explicit about potential security issues that can arise using finalization. In this case it is not a problem with code that uses finalization. Instead, finalization can be used by an attacker to attack sensitive code that hasn't properly defended itself. In particular, Guideline 7-3 / OBJECT-3 states in part,

Partially initialized instances of a non-final class can be accessed via a finalizer attack. The attacker overrides the protected finalize method in a subclass and attempts to create a new instance of that subclass. This attempt fails ... but the attacker simply ignores any exception and waits for the virtual machine to perform finalization on the partially initialized object. When that occurs the malicious finalize method implementation is invoked, giving the attacker access to this, a reference to the object being finalized. Although the object is only partially initialized, the attacker can still invoke methods on it....

Thus, the presence of the finalization mechanism in the platform imposes a burden on programmers who are trying to write high assurance code.

Finalization Adds Complexity to Specifications

The Java Platform is defined by several specifications, including specifications for the language, the virtual machine, and the class library APIs. Impact of finalization is spread thinly across all of these, but it repeatedly makes its presence felt. For example, finalization has a very subtle interaction with object creation (which is already complicated enough). Finalization also has appeared Java's public APIs, meaning that evolution of those APIs has (up to now) been required to remain compatible with previously specified behaviors. Evolving these specifications is made more costly the presence of finalization.

Finalization Adds Complexity to Implementations

This is mainly about garbage collectors. There are several garbage collection implementations, and all are required to pay the cost of implementing finalization. The implementations are quite good at minimizing the runtime overhead if finalization isn't used. However, the implementation still needs to be there, and it needs to be correct and well tested. This is an ongoing development and maintenance burden.

Summary

We've seen elsewhere that it's not recommended for programmers to use finalization. However, if something is not useful, it doesn't necessarily follow that it should be deprecated. The points above illustrate the fact that even if finalization isn't used, the mere presence of the mechanism in the platform imposes ongoing specification, development, and maintenance costs. Given the lack of usefulness of the mechanism and the costs it imposes, it makes sense to deprecate it. Eventually, getting rid of finalization will benefit everyone.

As of this writing (2019-06-04) there is no concrete plan to remove finalization from Java. However, it is certainly the intent to do so. We've deprecated the Object.finalize method, but have not marked it for removal. This is a formal recommendation that programmers stop using this mechanism. It's been known informally that finalization shouldn't be used, but of course it's necessary to take a formal step. In addition, certain finalize methods in library classes (for example, ZipFile.finalize) have been deprecated "for removal" which means that the finalization behavior of these classes may be removed from a future release. Eventually, we hope to disable finalization in the JVM (perhaps first optionally, and then later by default), and at some point in the future actually remove the finalization implementation from garbage collectors.

(Edit 2021-11-03: JEP 421 has just been posted, which proposes to deprecate finalization for removal. At this writing it's in the "candidate" state but I expect it will move forward. The deprecations added by this JEP are a formal notification that finalization will be removed at some point in a subsequent Java release. Perhaps not surprisingly, there's a fair overlap between the material in this answer and in the JEP, though the JEP is more precise and describes a moderate evolution in our thinking on the topic.)

(Edit 2022-04-04: JEP 421 Deprecate Finalization for Removal has been integrated and delivered in JDK 18.)

Stuart Marks
  • 120,620
  • 35
  • 192
  • 252
  • 1
    Finalization really is a complex matter. So there’s a small correction: only a finalizer trying to resurrect itself works only once. But a finalizer may resurrect a different encapsulated finalizer-reachable object, followed by creating a new instance of that wrapper which can resurrect the object again, a procedure that can be done an arbitrary number of times. Not that this was a recommended pattern… – Holger Jun 06 '19 at 12:03
  • 1
    @Holger True. The rule is about invocation of the `finalize` method, not about "resurrection" *per se*. I've updated the text to be more precise. – Stuart Marks Jun 06 '19 at 21:56
  • 2
    @StuartMarks `finalization can easily break subclass/superclass relationships` How? – Govinda Sakhare Jun 09 '19 at 10:16
  • 3
    @GovindaSakhare Briefly, if a subclass fails to call super.finalize() for any reason, finalization of the superclass wont occur. – Stuart Marks Jun 09 '19 at 17:51