java-native-access/jna · error
JNA: callback object has been garbage collected
Error message
JNA: callback object has been garbage collected
What it means
During callback dispatch, JNA creates a NewLocalRef of the stored callback object and checks IsSameObject against NULL — the standard test for whether the underlying object was garbage collected (the stored reference is weak). If collected, JNA prints this message, zeroes the return buffer, and skips the Java method invocation: the native caller gets a zeroed/void result and the callback silently does nothing.
Source
Thrown at native/dispatch.c:2078
jobject obj;
int attached = (*jvm)->GetEnv(jvm, (void *)&env, JNI_VERSION_1_4) == JNI_OK;
if (!attached) {
if ((*jvm)->AttachCurrentThread(jvm, (void *)&env, NULL) != JNI_OK) {
fprintf(stderr, "JNA: Can't attach native thread to VM for closure handler\n");
return;
}
}
// Give the callback its own local frame to ensure all local references
// are properly disposed
if ((*env)->PushLocalFrame(env, 16) < 0) {
fprintf(stderr, "JNA: Out of memory: Can't allocate local frame");
}
else {
obj = (*env)->NewLocalRef(env, cb->object);
if ((*env)->IsSameObject(env, obj, NULL)) {
fprintf(stderr, "JNA: callback object has been garbage collected\n");
if (cif->rtype->type != FFI_TYPE_VOID)
memset(resp, 0, cif->rtype->size);
}
else {
(*env)->CallVoidMethod(env, obj, MID_ffi_callback_invoke,
A2L(cif), A2L(resp), A2L(argp));
}
(*env)->PopLocalFrame(env, NULL);
}
if (!attached) {
if ((*jvm)->DetachCurrentThread(jvm) != 0) {
fprintf(stderr, "JNA: could not detach thread after callback handling\n");
}
}
}
View on GitHub (pinned to d036ad9781)
Solutions
- Keep a strong reference to every Callback instance you register (a field, static map, or list) for as long as the native side can invoke it.
- Provide an explicit unregister/dispose API call that removes the native registration before dropping the Java reference.
- If using a lambda or anonymous class, assign it to a long-lived variable rather than passing a fresh instance inline.
- On hitting the error, identify which callback was collected and re-register it while holding the reference.
Example fix
// before: callback only weakly held by native side
lib.register_callback(new MyCallback());
// after: strong Java-side reference
private static final MyCallback CB = new MyCallback();
void init() { lib.register_callback(CB); }
void shutdown() { lib.unregister_callback(CB); } Defensive patterns
Strategy: validation
Validate before calling
// Keep a strong reference registry for callbacks passed to native code:
private static final Set<Callback> LIVE_CALLBACKS = ConcurrentHashMap.newKeySet();
static void registerGuarded(Library lib, Callback cb) {
LIVE_CALLBACKS.add(cb);
lib.register_callback(cb);
} Type guard
static boolean isCallbackAlive(Callback cb) {
return cb != null && LIVE_CALLBACKS.contains(cb);
} Prevention
- Store every Callback instance in a long-lived Java field or registry while native code can invoke it.
- Pair every native registration with an explicit unregister that also removes the Java reference.
- Avoid passing fresh anonymous/lambda callbacks straight into native registration calls.
When it happens
Trigger: The Java object implementing the Callback was only weakly reachable (e.g. the caller stored the callback only in native code / passed it to the native library without keeping a strong Java reference), and the GC collected it before the native side invoked it.
Common situations: Passing an anonymous callback lambda to nativeLib.register(...) without storing it in a field; callback used only from C-side event tables; long-lived native subscriptions registered with short-lived Java wrappers.
Related errors
- JNA: could not detach thread after callback init
- JNA: Can't attach native thread to VM for closure handler
- JNA: Out of memory: Can't allocate local frame
- JNA: could not detach thread after callback handling
- JNA: Problems loading callback IDs: %s
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/8478cb363ab1ef5e.
Report an issue: GitHub.