Class NativeMemoryCleaner

java.lang.Object
express.mvp.myra.transport.memory.NativeMemoryCleaner

public final class NativeMemoryCleaner extends Object
Provides automatic native memory cleanup using the Cleaner API.

This class ensures that native resources are released even if explicit close() is not called. It uses phantom references to trigger cleanup when the owning object becomes unreachable.

Design Rationale

While explicit resource management via AutoCloseable is preferred, this cleaner provides a safety net for:

  • Exception paths that bypass normal cleanup
  • Complex object graphs where ownership is unclear
  • Third-party code that may not properly close resources

Usage Example

class NativeBuffer implements AutoCloseable {
    private final Arena arena;
    private final MemorySegment segment;
    private final Cleaner.Cleanable cleanable;

    public NativeBuffer(long size) {
        this.arena = Arena.ofConfined();
        this.segment = arena.allocate(size);

        // Register cleanup action - must not capture 'this'
        Arena arenaRef = this.arena;
        this.cleanable = NativeMemoryCleaner.register(this, () -> {
            arenaRef.close();
        });
    }

    @Override
    public void close() {
        cleanable.clean(); // Explicit cleanup, prevents GC-triggered clean
    }
}

Important Constraints

  • Cleanup actions must not reference the registered object (prevents GC)
  • Cleanup actions should be idempotent (may be called multiple times)
  • Cleanup runs on the cleaner thread, not the allocating thread

Statistics

This class tracks registration and cleanup statistics for monitoring and debugging.

See Also:
  • Method Details

    • register

      public static Cleaner.Cleanable register(Object object, Runnable cleanupAction)
      Registers an object for cleanup when it becomes phantom reachable.

      The cleanup action is called either:

      1. Explicitly via Cleaner.Cleanable.clean(), or
      2. Automatically when the object is garbage collected

      Critical: The cleanup action must not reference the registered object, as this would prevent garbage collection.

      Parameters:
      object - the object to monitor for cleanup
      cleanupAction - the action to run on cleanup (must not reference object)
      Returns:
      a Cleanable that can be used for explicit cleanup
    • getRegistrationCount

      public static long getRegistrationCount()
      Returns the total number of registrations.
      Returns:
      registration count
    • getExplicitCleanupCount

      public static long getExplicitCleanupCount()
      Returns the number of explicit cleanups (via clean()).
      Returns:
      explicit cleanup count
    • getGcCleanupCount

      public static long getGcCleanupCount()
      Returns the number of GC-triggered cleanups.
      Returns:
      GC cleanup count
    • getActiveCount

      public static long getActiveCount()
      Returns the number of active registrations (registered - cleaned).
      Returns:
      active registration count
    • resetStatistics

      public static void resetStatistics()
      Resets all statistics (for testing).
    • registerTracked

      public static NativeMemoryCleaner.TrackedCleanable registerTracked(Object object, Runnable cleanupAction)
      Creates a tracked cleanable that properly distinguishes explicit vs GC cleanup.
      Parameters:
      object - the object to monitor
      cleanupAction - the cleanup action
      Returns:
      a cleanable that tracks cleanup type