Android NDK Interview Questions

JNI, native memory, and performance.

50 questions in this topic · 8 sample questions below

Practice NDK in the quiz engine

Sample questions

  1. What is the primary purpose of the Android NDK?

    • To let you build performance-critical parts of an app in C and C++ — correct
    • To replace Gradle as the build system for all Android apps
    • To generate Kotlin bindings automatically from XML layouts
    • To run apps without the Android Runtime (ART)

    Why: The NDK lets you compile C/C++ into native libraries loaded via JNI, typically for CPU-heavy work. It does not replace Gradle, which still orchestrates the build, and it never removes the need for ART.

  2. In JNI, what is the fundamental difference between a JavaVM pointer and a JNIEnv pointer?

    • JavaVM is per-thread while JNIEnv is process-wide and shareable
    • JavaVM is process-wide and shareable, while JNIEnv is valid only on the thread it was obtained on — correct
    • They are interchangeable aliases for the same underlying structure
    • JNIEnv can start the VM, while JavaVM only provides string functions

    Why: There is one JavaVM per process and it may be cached and shared across threads, but each JNIEnv is thread-local and must never be reused on another thread. The reversed claim confuses which one is thread-bound.

  3. A native thread you created with pthread_create wants to call into Java. What must it do first?

    • Nothing; any thread can use the JNIEnv passed to a previous native call
    • Call System.loadLibrary again from the native thread
    • Call AttachCurrentThread on the JavaVM to obtain a valid JNIEnv — correct
    • Call GetEnv, which always returns a valid JNIEnv on any thread

    Why: A thread not created by the JVM has no JNIEnv until you AttachCurrentThread, and it should DetachCurrentThread before exiting. Reusing a JNIEnv from another thread is undefined behavior, and GetEnv returns JNI_EDETACHED for unattached threads.

  4. You cache a jclass returned by FindClass in a static C++ variable during a JNI call and reuse it on later calls. What is the latent bug?

    • jclass values change every time the class is verified by ART
    • Static C++ variables are not allowed in JNI shared libraries
    • FindClass cannot be called more than once per class in a process
    • The returned reference is a local reference that becomes invalid after the native call returns — correct

    Why: FindClass returns a local reference, which is only valid for the duration of the current native call; to cache it you must promote it with NewGlobalRef. Caching the raw local reference leads to use of a stale, freed reference on the next call.

  5. When are JNI local references normally freed?

    • Automatically when the native method returns to Java — correct
    • Only when the garbage collector runs a full heap collection
    • Immediately after the line of code that created them executes
    • Never; every local reference must be manually deleted or it leaks permanently

    Why: Local references are freed automatically when the native method returns, so short calls rarely need manual cleanup. They are not freed line-by-line, and while long-running loops can exhaust the local reference table, they do not leak forever once the frame is popped.

  6. A native loop creates thousands of jobject local references per iteration without deleting them and eventually aborts. What is the correct fix?

    • Convert each jobject to a global reference inside the loop
    • Call DeleteLocalRef on each object once you are done with it inside the loop — correct
    • Call System.gc from native code every few iterations
    • Increase the heap size in the manifest with largeHeap

    Why: The local reference table has a bounded capacity (commonly 512 guaranteed slots), so unbounded creation in a loop overflows it; DeleteLocalRef frees slots as you go. Global references would make the leak worse, and largeHeap affects the Java heap, not the JNI reference table.

  7. What does GetStringUTFChars return, and why must ReleaseStringUTFChars be called?

    • A UTF-16 buffer that is always a direct pointer into the Java heap
    • A brand-new Java String object that must be deleted with DeleteLocalRef
    • A modified-UTF-8 C string that may be a copy, so releasing it frees the copy or unpins the array — correct
    • A standard UTF-8 string identical to what std::string uses internally

    Why: GetStringUTFChars gives a null-terminated modified-UTF-8 buffer that the runtime may allocate as a copy, so the matching Release is required to avoid a native memory leak. It is modified-UTF-8, not standard UTF-8, which matters for embedded null bytes and supplementary characters.

  8. How does modified UTF-8 used by GetStringUTFChars differ from standard UTF-8?

    • It is actually little-endian UTF-16 with a byte-order mark
    • It is identical to standard UTF-8 in every respect
    • It drops all multi-byte sequences and is effectively ASCII only
    • The null character is encoded as two bytes and supplementary characters use surrogate pair encoding — correct

    Why: Modified UTF-8 encodes U+0000 as the two-byte sequence 0xC0 0x80 so C strings never contain an interior null, and it encodes characters above the BMP as CESU-8 style surrogate pairs. Treating the buffer as standard UTF-8 can corrupt emoji and text with embedded nulls.

Practice all 50 NDK questions

These 8 are a sample. The full NDK bank is scored, tracks your progress, and explains every answer.

Open the quiz

More Android interview topics