Some developers used JNA to call native C/C++ interfaces of Dynamsoft Barcode Reader in Java program. The app ran slowly and sometimes crashed. Based on the use case, I created a simple project for building JNA and JNI on Windows. The sample does not only show how to invoke native code but also share how to check the Java thread stack size and solve the stack overflow issue on Windows.
Download and Installation
Accessing Native Code via JNA and JNI
Open Eclipse to create a new project. The structures of JNA and JNI folders are almost the same.
Create the Java function decodefile() for JNA and JNI:
For JNA, you just need to create a standard function and export it. For JNI, you have to comply with the JNI naming convention.
Building shared libraries with CMake
Copy shared libraries to <Project Root>/jna(jni)/platforms/win:
To build the shared library for JNI, replace ‘jnadbr’ with ‘jnidbr’.
Build the project for 64-bit Java runtime:
cd jnamkdir buildcd buildcmake -G"Visual Studio 15 2017 Win64" ..cmake --build . --config Release --target install
Create Demo.java for test:
Run the app:
javac -cp libs\jna-3.0.9.jar src\com\dynamsoft\*.javajava -cp libs\jna-3.0.9.jar;src\ com.dynamsoft.Demo
Why is running JNA much slower than running JNI?
The native code is the same, why the performance is different? The only possible reason is when calling the native method the first time it takes a long time to initialize the JNA environment.
We can call the native method to initialize the JNA environment before measuring the performance.
Build and rerun the app. The JNA performance of invoking native method looks no different to JNI.
Now we get the conclusion that using JNA takes extra loading time.
Java VM Stack Overflow Exception
The stack overflow exception showed up when runtime environment switched from 64-bit to 32-bit.
According to https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/crashes001.html, the issue is caused by thread stack size. To solve the issue, we’d better know the default thread stack size. Let’s try the following command:
java -XX:+PrintFlagsFinal -version | grep ThreadStackSize
java -XX:+PrintFlagsFinal -version | findstr ThreadStackSize
The value of stack size is 0 on Windows. Maybe the answer is in the source code.
Download and install TortoiseHg.
Get JVM source code:
Search for ‘stack size’ to find the following informative paragraph.
To verify whether the default stack size is 320K on Windows, I tried the code snippet located in os_windows.cpp:
To avoid stack overflow exception, we should allocate big chunks of memory on the heap instead of the stack.
Re-compile the native code in x86 mode:
cd jnamkdir buildcd buildcmake ..cmake --build . --config Release --target install
Compile and run the Java code with 32-bit JDK:
"E:\Program Files (x86)\Java\jdk1.8.0_191\bin\javac.exe" -cp libs\jna-3.0.9.jar src\com\dynamsoft\*.java"E:\Program Files (x86)\Java\jdk1.8.0_191\bin\java.exe" -cp libs\jna-3.0.9.jar;src\ com.dynamsoft.Demo
We can see the default stack size is 320K by default on Windows. To enlarge the stack size, append -Xss option when running Java program:
"E:\Program Files (x86)\Java\jdk1.8.0_191\bin\java.exe" -Xss1024 -cp libs\jna-3.0.9.jar;src\ com.dynamsoft.Demo
Originally published at www.codepool.biz on October 21, 2018.