JVM.Advanced.How does the JVM handle native method calls?

🔗 What is a Native Method?

A native method is a method declared in Java, but implemented in a language like C or C++. These methods are usually marked with the native keyword, for example:

public class Example {
    public native void doSomethingNative();
}

⚙️ How the JVM Handles Native Method Calls

Step 1: Declaration in Java Code

You declare a method as native in your Java code, meaning the method body is not written in Java — the JVM knows it has to delegate this call to native (platform-specific) code.


Step 2: Native Code Implementation

The actual implementation is written in a native language, usually C or C++. This implementation can directly access OS resources, hardware, or existing native libraries.


Step 3: Loading the Native Library

Before you can call the native method, the JVM must load the corresponding native library using:

System.loadLibrary("libraryName");

Step 4: Method Table Linking (JNI)

Once the library is loaded, the JVM links the native method to the correct function pointer in the native library. This is done using the Java Native Interface (JNI).

  • JNI defines a standard way for Java code to call native code and vice versa.
  • The native function signature must match what the JVM expects — this includes:
    • Naming convention (Java_package_class_method)
    • Parameter and return types mapped to JNI types (like jstring, jint, etc.)

Example C function for a Java method:

JNIEXPORT void JNICALL Java_Example_doSomethingNative(JNIEnv *env, jobject thisObj) {
    // Native implementation
}

Step 5: Invocation

When the Java code calls the native method, the JVM:

✅ Looks up the native method in an internal method table.
✅ Uses a function pointer to jump directly to the native code.
✅ Converts arguments from Java types (like String) into JNI types (like jstring).
✅ Transfers control to the native function.


Step 6: Native Method Execution

  • The native method runs outside the JVM — in native code, you have direct access to system resources.
  • You can still use the JNIEnv pointer to interact with the JVM, if needed (like calling back into Java).

Step 7: Return and Cleanup

  • After the native method finishes, the native return value (if any) is converted back into a Java type.
  • The JVM resumes execution as if a regular Java method had returned.

🚀 Quick Visualization

+------------------+
|   Java Code      |
| (native method)  |
+------------------+
        |
        v
+------------------+
|     JVM          |
| (Method table +  |
|  JNI glue code)  |
+------------------+
        |
        v
+------------------+
|  Native Library  |
|  (C/C++ code)    |
+------------------+

📜 Example Flow

public class Example {
    static {
        System.loadLibrary("mylib"); // Load native code
    }

    public native void doSomethingNative(); // Native method
}

Native C code:

#include <jni.h>
#include "Example.h"

JNIEXPORT void JNICALL Java_Example_doSomethingNative(JNIEnv *env, jobject obj) {
    printf("Hello from native code!\n");
}

✅ Summary Table

StepWhat Happens
DeclareJava defines a native method.
ImplementNative code provides real implementation.
LoadSystem.loadLibrary() loads the native library.
LinkJVM links the method to native code (via JNI).
CallJVM converts arguments and calls native code.
ReturnNative method returns result to JVM.

⚠️ Things to Watch Out For

  • Crashes in native code will crash the whole JVM (unlike exceptions in Java).
  • Manual memory management is required in native code.
  • JNI is low-level and can be error-prone — careful coding is needed to avoid leaks or undefined behavior.
This entry was posted in Без рубрики. Bookmark the permalink.