{"record":{"id":"a28ba515fee21671","repo":"apache/hadoop","slug":"cannot-mlock-a-non-direct-bytebuffer","errorCode":null,"errorMessage":"Cannot mlock a non-direct ByteBuffer","messagePattern":"Cannot mlock a non-direct ByteBuffer","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/nativeio/NativeIO.java","lineNumber":477,"sourceCode":"    }\n\n    static native void mlock_native(\n        ByteBuffer buffer, long len) throws NativeIOException;\n\n    /**\n     * Locks the provided direct ByteBuffer into memory, preventing it from\n     * swapping out. After a buffer is locked, future accesses will not incur\n     * a page fault.\n     * \n     * See the mlock(2) man page for more information.\n     * \n     * @throws NativeIOException\n     */\n    static void mlock(ByteBuffer buffer, long len)\n        throws IOException {\n      assertCodeLoaded();\n      if (!buffer.isDirect()) {\n        throw new IOException(\"Cannot mlock a non-direct ByteBuffer\");\n      }\n      mlock_native(buffer, len);\n    }\n\n    /**\n     * Unmaps the block from memory. See munmap(2).\n     *\n     * There isn't any portable way to unmap a memory region in Java.\n     * So we use the sun.nio method here.\n     * Note that unmapping a memory region could cause crashes if code\n     * continues to reference the unmapped code.  However, if we don't\n     * manually unmap the memory, we are dependent on the finalizer to\n     * do it, and we have no idea when the finalizer will run.\n     *\n     * @param buffer    The buffer to unmap.\n     */\n    public static void munmap(MappedByteBuffer buffer) {\n      if (CleanerUtil.UNMAP_SUPPORTED) {","sourceCodeStart":459,"sourceCodeEnd":495,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/nativeio/NativeIO.java#L459-L495","documentation":"NativeIO.mlock(ByteBuffer, long) pins memory with mlock(2), which requires a stable native address; only direct ByteBuffers (ByteBuffer.allocateDirect) have one. Heap buffers live on the movable GC heap, so the method rejects them with IOException before entering JNI. It is a precondition on buffer type, not an environmental failure.","triggerScenarios":"Passing ByteBuffer.allocate(n) or ByteBuffer.wrap(byte[]) to NativeIO.mlock — common when refactoring byte[]-based code to the ByteBuffer API or when a caller upstream chooses the buffer type (HDFS short-circuit / caching code paths that use mlock).","commonSituations":"Shared-memory and page-pinning features (short-circuit read caches, mlock-based block caching) receiving heap buffers from a refactored caller; unit tests allocating convenient heap buffers.","solutions":["Allocate with ByteBuffer.allocateDirect(capacity) before calling mlock.","Pool direct buffers — they are expensive to allocate, so reuse them instead of converting per call.","Enforce directness at the API boundary: check buffer.isDirect() (or assert) as soon as the buffer enters your module."],"exampleFix":"// before\nByteBuffer buf = ByteBuffer.allocate(len);\nNativeIO.mlock(buf, len); // IOException: non-direct\n\n// after\nByteBuffer buf = ByteBuffer.allocateDirect(len);\nNativeIO.mlock(buf, len);","handlingStrategy":"validation","validationCode":"if (!buffer.isDirect()) {\n  throw new IllegalArgumentException(\"mlock requires a direct ByteBuffer\");\n}\nNativeIO.mlock(buffer, len);","typeGuard":"private static ByteBuffer requireDirect(ByteBuffer b) {\n  if (b == null || !b.isDirect()) {\n    throw new IllegalArgumentException(\"direct ByteBuffer required\");\n  }\n  return b;\n}","tryCatchPattern":null,"preventionTips":["Standardize on ByteBuffer.allocateDirect in the buffer factory so all downstream native calls are safe.","Document directness requirements on any API that hands buffers to native code.","Pool and explicitly release direct buffers; do not convert heap→direct per call in hot paths."],"tags":["native-io","mlock","bytebuffer","memory"],"backgroundTag":"bytebuffer-not-direct","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}