java-native-access/jna · warning
JNA: callback object has been garbage collected
Error message
JNA: callback object has been garbage collected
What it means
In invoke_callback, when the Java callback object has been garbage collected, JNA prints this warning to stderr, and if the callback has a non-void return type, zeroes the native return buffer. Native code still holds the trampoline, but the Java side object is unreachable, so the callback cannot be invoked.
Source
Thrown at native/callback.c:402
}
}
}
}
}
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
return 0;
}
static void
invoke_callback(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbargs) {
jobject self;
void *oldresp = resp;
self = (*env)->NewLocalRef(env, cb->object);
// Avoid calling back to a GC'd object
if ((*env)->IsSameObject(env, self, 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 if (cb->direct) {
unsigned int i;
void **args = alloca((cif->nargs + 3) * sizeof(void *));
args[0] = (void *)&env;
args[1] = &self;
args[2] = &cb->methodID;
memcpy(&args[3], cbargs, cif->nargs * sizeof(void *));
// Note that there is no support for CVT_TYPE_MAPPER here
if (cb->conversion_flags) {
for (i=0;i < cif->nargs;i++) {
switch(cb->conversion_flags[i]) {
case CVT_INTEGER_TYPE:
case CVT_POINTER_TYPE:View on GitHub (pinned to d036ad9781)
Solutions
- Keep a strong reference to the callback object for as long as native code may invoke it (store it in a field or static collection).
- Call Native.unregister() (or dispose the library) when done so native no longer invokes stale trampolines.
- Treat the stderr warning as a bug indicator: audit callback lifetimes rather than suppressing it.
Example fix
// before nativeLib.setCallback(new MyCallback()); // only referenced by native // after private MyCallback callback = new MyCallback(); // strong field reference nativeLib.setCallback(callback);
Defensive patterns
Strategy: fallback
Prevention
- Store callback objects in long-lived fields or a static registry so GC cannot collect them
- Call Native.unregister() when the callback is no longer needed
- For async native calls, never use method-local callback instances
- Monitor stderr for this warning in CI/native logs
When it happens
Trigger: A Java Callback object becomes unreachable and is GC'd while its native function pointer is still registered/called by native code — e.g. the callback was not kept in a Java field, or the library was not explicitly releases the callback via Native.unregister().
Common situations: Storing callbacks only in local variables while native code calls them asynchronously/later; long-lived native threads invoking callbacks after the creating Java scope exits.
Related errors
- JNA: Unhandled arg conversion type %d
- JNA: error handling callback exception, continuing
- JNA: Likely memory leak here
- JNA: callback object has been garbage collected
- Win32Exception(rc)
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/782cac523cab206f.
Report an issue: GitHub.