API reference

NativeHandleCleaner Object

Reachability-driven cleanup for JVM wrappers that own native handles.
Use this from a wrapper class when you want the native handle to be released automatically once the wrapper becomes unreachable, with the option to release it eagerly via destroy().
class SceneFoo private constructor() {
  private val state = NativeHandleCleaner.NativeState(/* handle */)
   private val token = NativeHandleCleaner.register(this, state, "SceneFoo") { h ->
     SceneFoo.nativeDestroyStatic(h)
   }
   fun destroy() = token.cleanNow()
 }

The cleanup lambda MUST NOT capture the wrapper (transitively) — typically a method reference to a top-level or @JvmStatic external function.
ART does not see native heap pressure — a dropped wrapper holding multi-MiB of native memory may sit unreclaimed indefinitely while ART is happy with the JVM heap. For time-critical bulk memory, call destroy() rather than relying on GC. The cleaner is a safety net, not the primary mechanism for prompt freeing. Use NativeHandleCleaner.nudgeGc after dropping bulk wrappers if you need cleanup to run sooner.

Signature

object NativeHandleCleaner

Methods

nudgeGc ()
Hint that now is a good time to GC unreachable wrappers. Rate-limited; safe to over-call.
Useful right after dropping bulk native memory (e.g. caches of large textures): without a hint, ART may defer GC for many seconds because it does not see native heap pressure, leaving the cleaner NativeHandleCleaner.Tokens for those wrappers parked. Runtime.gc() is itself a hint — ART may ignore it but in practice usually runs.
Signature
fun nudgeGc()
register ( referent , state , label , cleanup )
Register NativeHandleCleaner.register for cleanup-on-unreachability.
Signature
fun register(referent: Any, state: NativeHandleCleaner.NativeState, label: String, cleanup: (Long) -> Unit): NativeHandleCleaner.Token
Parameters
referent: Any  The wrapper object whose unreachability triggers cleanup. The NativeHandleCleaner.register callback MUST NOT capture this object (transitively), or cleanup will never fire.
state: NativeHandleCleaner.NativeState  Holder for the native handle. Zeroed when cleanup runs.
label: String  Short tag for diagnostic logging.
cleanup: Function1  Action that releases the native handle. Receives the (always non-zero) handle. Runs on the main looper for the GC path, or on the calling thread for explicit NativeHandleCleaner.Token.cleanNow. Typically a static method reference.
Returns
NativeHandleCleaner.Token

Inner Classes

NativeState Class

Modifiers: final
Mutable holder for a native handle. Zeroed when cleanup runs.

Signature

class NativeState(var handle: Long)

Constructors

NativeState ( handle )
Signature
constructor(handle: Long)
Parameters
handle: Long
Returns
NativeHandleCleaner.NativeState

Properties

handle : Long
[Get][Set]
Signature
var handle: Long

Token Class

Extends PhantomReference
Modifiers: final
Returned by NativeHandleCleaner.register. Call NativeHandleCleaner.Token.cleanNow to release the native handle eagerly; otherwise it fires when the registered wrapper becomes unreachable.

Signature

class Token : PhantomReference<Any> 

Methods

cleanNow ()
Release the native handle now, synchronously on the calling thread. Idempotent and safe to call from any thread (subject to the cleanup callback's own thread-safety).
Signature
fun cleanNow()
clear ()
Signature
open fun clear()
enqueue ()
Signature
open fun enqueue(): Boolean
Returns
Boolean
get ()
Signature
open override fun get(): Any?
Returns
Any?
isEnqueued ()
Signature
open fun isEnqueued(): Boolean
Returns
Boolean