Friday, November 26, 2021

The final days of finalizers in Java

If you are developing in Java long enough, you are surely aware of the Object::finalize() method and the concept of the finalizers in general.

protected void finalize() throws Throwable
    
...
Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. A subclass overrides the finalize method to dispose of system resources or to perform other cleanup.
...

This reasonably good idea has gotten quite bad reputation over the years and definitely is one of the worst nightmares of the JVM developers. There are enough details and horror stories on the web related to finalizers (who did not implement it at least once?), but the end is near: JEP-421: Deprecate Finalization for Removal, proposed to become a part of the JDK-18 release, kicks off the process to phase finalizers out.

In this rather short post we are going to talk about java.lang.ref.Cleaner, the mechanism alternative to the finalizers, which allows to perform the cleaning actions once the corresponding object instance becomes phantom reachable. It was introduced by JDK-8138696 and is available starting from JDK-9 and onwards.

The usage of java.lang.ref.Cleaner is pretty straightforward (although advanced usage scenarios are also possible):

To illustrate it, let us consider a quick example. Assume we have been designing a ResourceAccessor class that accesses (or even allocates) some resources (possibly, natives ones, which are outside of the JVM control).

import java.lang.ref.Cleaner;

public class ResourceAccessor implements AutoCloseable {
    private static final Cleaner cleaner = Cleaner.create();
    private final Cleaner.Cleanable cleanable;
    private final Resource resource;

    public ResourceAccessor() {
        this.resource = new Resource();
        this.cleanable = cleaner.register(this, cleaner(resource));
    }

    @Override
    public void close() throws Exception {
        cleanable.clean();
    }

    private static Runnable cleaner(Resource resource) {
        return () -> {
            // Perform cleanup actions
            resource.release();
        };
    }
}

The ResourceAccessor allocates the resource and registers the cleanup action on construction, keeping the reference to Cleaner.Cleanable instance. It also implements AutoCloseable interface and the close() method just delegates to the Cleaner.Cleanable::clean.

Please notice that cleanup action should not hold any references to the object instance registered for cleanup, otherwise that instance will not become phantom reachable and the cleaning action will not be invoked automatically. This is why we have wrapped the lamdba expression behind the cleanup action inside the static method. Alternatively, usage of the standalone class or static nested class that implements Runnable is also possible. Essentially, this is all we need!

Although java.lang.ref.Cleaners provides better and safer alternative to the finalizers, you should not overuse them. The AutoCloseable and try-with-resources idiom should be the preferred approach to manage resources in the majority of situations.

try (final ResourceAccessor resource = new ResourceAccessor()) {
    // Safely use the resource            
}

In these rare conditions when the lifespan of the resource is not well defined, the java.lang.ref.Cleaner is here to help. If you are curious how JDK is using java.lang.ref.Cleaner internally, please take a look at, for example, java.util.Timer or sun.nio.ch.NioSocketImpl classes.

Thursday, September 30, 2021

Chasing Java's release train: JDK-17, the next big thing

Here we go, JDK-17, the next LTS release, just became generally available. It is an important milestone for the OpenJDK for years to come but sadly, Project Loom, the most anticipated improvement of the JVM platform, was not able to make it, despite the extraordinary progress being made. Well, if you are still on JDK-8, like the majority of us, who cares, right?

Not really, for example Spring Framework had made an announcement quite recently to support JDK-17 as a baseline. It is very likely others will follow, leaving JDK-8 behind. So what is new in JDK-17?

And what is happening on the security side of things? Besides SecurityManager deprecation (JEP-411), it is worth to mention:

JDK-17 is an important release. First of all, it is going to become the de-facto choice for green field projects for the next couple of years. Second, the ones who are still on JDK-8 would migrate straight to JDK-17, skipping JDK-11 entirely (there are hardly any reasons to migrate to JDK-11 first). Consequently, the third, migration from JDK-11 to JDK-17 requires comparatively low efforts (in most cases), it is logical to expect seeing the JDK-17 kicking out JDK-11.

Are we done yet? Luckily, not at all, the JDK release train is accelerating, shifting from three years LTS releases to two years. Hopefully, this strategic decision would speed up the pace of migration, specifically for enterprises, where many are stuck with older JDKs.

And let us not forget, the JDK-18 is already in early access! It comes with the hope that Project Loom is going to be included, in some form or the other.

Thursday, July 29, 2021

Chasing Java's release train, from 8 to 16. Part 3: The avalanche of releases ...

Undoubtedly, JDK-11 was an import milestone but once the dust settled, another target appeared on the horizon, JDK-17, the next LTS release. But between those, the avalanche of new releases and features was unleashed.

JDK 12

JDK-12 didn't have too many features packed into it nonetheless it includes considerable number of improvements, especially to G1 garbage collector.

Besides the changes we have talked about, JDK-12 has delivered quite a number of the security enhancements, notably:

JDK 13

Just when the excitement after JDK-12 release faded away, the JDK-13 was ready to come along. By all means, it was a minor one from the features perspective.

A fair amount of the security enhancements in JDK-13 is certainly worth checking out.

JDK 14

Going further, the JDK-14 kept the steady pace of innovation and was bundled with quite a useful set of changes. Let us take a look at the most interesting ones.

The JDK-14 was not without the security enhancements, the most disruptive of those was probably the removal of the java.security.acl APIs (see please JDK-8191138).

JDK 15

Arguably, the JDK-15 was a major one for the reasons that many experimental and preview features had finally graduated to mainstream and became ready for production use. Let us start from those.

Besides JEP-339 (EdDSA), there are quite a few security enhancements in JDK-15, the ones that deserve mentioning are:

JDK 16

If JDK-15 qualified as a major one then JDK-16 could be easily stamped as huge, packed with new language features, tooling and GC improvements. Let us dig right in.

Many security enhancements were baked into JDK-16, just to mention a couple:

JDK 17: Mostly There

Nonetheless the JDK-17 is not out yet, it has entered Rampdown Phase Two, meaning its feature set is frozen and no further JEPs will be targeted to this release. In the upcoming part we are going to cover it right when its release is announced. Stay tuned!