java-native-access/jna · error

JNA: Out of memory: Can't allocate local frame

Error message

JNA: Out of memory: Can't allocate local frame

What it means

dispatch_callback pushes a JNI local frame (PushLocalFrame(env, 16)) so callback-local references are freed deterministically. If PushLocalFrame fails (returns < 0), it is an OutOfMemoryError condition; JNA prints this message but still calls invoke_callback, so local references created by the callback leak into the outer frame.

Source

Thrown at native/callback.c:745

      tls->needs_detach = needs_detach;
      tls->jvm_thread = JNI_FALSE;
    }
    // Dispose of allocated memory
    free((void *)args.name);
    if (args.group) {
      (*env)->DeleteWeakGlobalRef(env, args.group);
    }
  }

  if (!tls) {
    fprintf(stderr, "JNA: couldn't obtain thread-local storage\n");
    return;
  }

  // Give the callback glue 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\n");
  }
  else {
    invoke_callback(env, cb, cif, resp, cbargs);
    // Make note of whether the callback wants to avoid detach
    needs_detach = tls->needs_detach && !tls->jvm_thread;
    (*env)->PopLocalFrame(env, NULL);
  }
  
  if (needs_detach) {
    if ((*jvm)->DetachCurrentThread(jvm) != 0) {
      fprintf(stderr, "JNA: could not detach thread\n");
    }
  }
}

const char* 
JNA_callback_init(JNIEnv* env) {
#ifdef PTHREADS

View on GitHub (pinned to d036ad9781)

Solutions

  1. Free memory / increase -Xmx; verify the process is not near its native memory limit.
  2. Fix any code path that leaks JNI local references (missing DeleteLocalRef) on callback threads.
  3. Wrap callback dispatch with explicit PushLocalFrame/PopLocalFrame in your own native glue to bound reference growth.
  4. Reduce callback frequency or batch work across fewer native->Java transitions.
Defensive patterns

Strategy: retry

Prevention

When it happens

Trigger: PushLocalFrame returns negative because the JVM is out of memory — no native handle space remains to allocate the new local frame on the callback thread.

Common situations: Heap/native memory exhaustion during heavy callback traffic, a callback thread that leaked huge numbers of local references previously, tiny -Xmx with many attached threads.

Related errors


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/e0e76be91237b0a7. Report an issue: GitHub.