0

I need to use a native pointer (an int) for an LWJGL project, and the tutorial I'm following proposes to use the Object.finalize() method. But, since it's deprecated since Java 9, I looked for better solutions. I found the Cleaner/Cleanable duo on the Oracle documentation and tried to use it, but I don't know if I'm doing it right. Is this the way to go?

import java.lang.ref.Cleaner;

public class PointerUsingObject
{
    // A native pointer
    private int pointer;
    
    private static final Cleaner cleaner = Cleaner.create();
    private final Cleaner.Cleanable cleanable;

    public PointerUsingObject()
    {
        cleanable = cleaner.register(this, new Runnable()
        {
            @Override
            public void run()
            {
                // Free the pointer
            }
        });
    }
    
    
    // Is called to destroy the object when I'm sure not to use it anymore
    public void destroy()
    {
        cleanable.clean();
    }
}
Debaug
  • 452
  • 4
  • 14
  • 1
    [you could read this also](https://stackoverflow.com/questions/65766061/cleaning-up-weak-reference-caches-with-finalizers/65799297#65799297) – Eugene May 25 '21 at 17:50
  • 2
    You are doing precisely what [the documentation](https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/ref/Cleaner.html) warns about: “*An ‘inner’ class, anonymous or not, must not be used because it implicitly contains a reference to the outer instance, preventing it from becoming phantom reachable.*” – Holger May 26 '21 at 07:54

1 Answers1

1

OK, so as someone pointed out, I should instantiate a static nested class to manage the cleaning, as following:

import java.lang.ref.Cleaner;

public class PointerUsingObject implements AutoCloseable
{
    // A native pointer
    private int pointer;
    
    private static final Cleaner cleaner = Cleaner.create();
    private final Cleaner.Cleanable cleanable;

    public PointerUsingObject()
    {
        cleanable = cleaner.register(this, new CleanMethod(pointer));
    }

    @Override
    public void close() throws Exception
    {
        cleanable.clean();
    }
    
    private static class CleanMethod implements Runnable
    {
        private int pointer;
        
        public CleanMethod(int pointer)
        {
            this.pointer = pointer;
        }
        
        @Override
        public void run()
        {
            // Free the pointer
        }
    }
}

I also implemented the AutoCloseable interface and replaced the destroy() method with the close() method.

Debaug
  • 452
  • 4
  • 14
  • 1
    Note that using a lambda expression is possible but it’s recommended to put it into a `static` factory method to ensure that accidentally capturing `this` is impossible, e.g. `static Runnable cleanMethod(int pointer) { return () -> {/* free the pointer */ }; }` which can be used like `cleanable = cleaner.register(this, cleanMethod(pointer));` in the constructor. – Holger May 27 '21 at 10:32