What does a JVM have to do when calling a native method?
Calling a JNI method from Java is rather expensive comparing to a simple C function call.
HotSpot typically performs most of the following steps to invoke a JNI method:
- Create a stack frame.
- Move arguments to proper register or stack locations according to ABI.
- Wrap object references to JNI handles.
- Obtain
JNIEnv*
andjclass
for static methods and pass them as additional arguments. - Check if should call
method_entry
trace function. - Lock an object monitor if the method is
synchronized
. - Check if the native function is linked already. Function lookup and linking is performed lazily.
- Switch thread from
in_java
toin_native
state. - Call the native function
- Check if safepoint is needed.
- Return thread to
in_java
state. - Unlock monitor if locked.
- Notify
method_exit
. - Unwrap object result and reset JNI handles block.
- Handle JNI exceptions.
- Remove the stack frame.
The source code for this procedure can be found at SharedRuntime::generate_native_wrapper.
As you can see, an overhead may be significant. But in many cases most of the above steps are not necessary. For example, if a native method just performs some encoding/decoding on a byte array and does not throw any exceptions nor it calls other JNI functions. For these cases HotSpot has a non-standard (and not known) convention called Critical Natives
, discussed here.
Does JVM halt when calling native code?
Threads running native code will not halt JVM.
As soon as JNI method is called, Java thread switches to _thread_in_native
state. Threads in this state are not counted during safepoint operations, i.e. when a stop-the-world event occurs (like garbage collection), JVM does not stop these threads. Conversely, threads in native state cannot stop JVM unless they perform a JNI upcall. When a native method returns, the thread switches back to _thread_in_Java
state.
JNI How to call java and call back native, And how to get JVM std io
To access native methods, you still must call System.LoadLibrary()
. The spec explains that your Driver.java should look contain:
public class Driver {
static { System.loadLibrary("driver"); } // this name must be matched!
public static native int nativeSum(int a, int b);
public static int sum(int a, int b) {
return nativeSum(a, b);
}
}
and in your main.cpp,
extern "C" JNIEXPORT jint JNICALL Java_Driver_nativeSum(JNIEnv*, jclass, jint a, jint b) {
std::cout << "Native invoked " << std::endl;
return a + b;
}
extern "C" JNIEXPORT jint JNI_OnLoad_driver // this suffix must match the name used in Java
(JavaVM *vm, void *reserved) {
std::cout << "Native loaded" << std::endl;
return JNI_VERSION_1_8;
}
Make sure that the linker keeps both Java_Driver_nativeSum
and JNI_OnLoad_driver
exported in your binary.
As for your first question, there is no separate JVM stdio stream, Java reads from the same fd=0
and writes to same fd=1
as all others.
Calling built-in java native methods
No you can't. It's designed that way on purpose; you would override the API contracts if you could.
In any event, the standard library wrapper code is very slight and with JIT compilers you shouldn't notice any speed impact.
Furthermore, the implementation of those methods are not part of the API spec. What is "native" for one implementation of Java doesn't have to be for another.
Can one native method be called from another native method?
Calling one native method from another is in fact permitted. At least, I did not receive any errors or warnings when I did this. But the call must include the full function name as expected of any native method - i.e. Java_com_project_package_JSQ_destroy
and the parameters should include:
- the JNI environment
- jobject Object
- parameters expected by the method. In this case, shdl
Therefore, the call must be like so:
Java_com_project_package_JSQ_destroy(env, <jobject_object_name>, shdl);
It should place the call to destroy method. However, it doesn't really adhere to the purpose served by the Java Native Interface which is a layer used to allow Java code to make calls to and be called by native applications and libraries written in other languages (here, C++).
Related Topics
@Valid Annotation Is Not Validating the List of Child Objects
Do Not Use System.Out.Println in Server Side Code
Process Thymeleaf Variable as HTML Code and Not Text
How to Compile Jrxml to Get Jasper
How to Add Close Button to a Jtabbedpane Tab
How to Exit a While Loop in Java
Java: Why am I Required to Initialize a Primitive Local Variable
Import Com.Sun.Image.Codec.Jpeg.*
How to Add Maven Dependencies While Using the Maven-Jlink-Plugin
Drawing a Component to Bufferedimage Causes Display Corruption
How to Convert a Java Object to Xml with Open Source APIs
Java Swing Jtextfield Set Placeholder
Eclipse Error ... Cannot Be Resolved to a Type
Understanding the etc/Gmt Time Zone