I'm using a library that calls the JNI_CreateJavaVM function inside the library code. However, I also need some JNI Wrappings and I need to call the same function JNI_CreateJavaVM to get the JNIEnv* to my application.
But the second call is failing.
is there any way to do this?
The library does not support getting or setting the JNIEnv* created inside the library.
You cannot create more than one JVM from the same process:
As of JDK/JRE 1.2 , creation of multiple VMs in a single process is not supported.
You may be able to attach your current thread to the existing JVM though using AttachCurrentThread function. See the docs for the Invocation API. The equivalent document in Java 15 simply states:
Creation of multiple VMs in a single process is not supported.
You will need a pointer to the JavaVM object. See if JNI_GetCreatedJavaVMs() can help you, I'm not sure if this is per-process (in which case it will only ever be a single element list) or per machine. In either case the JavaVM will have to be the one that the library is using or you probably will not be doing what you want. If you can access that then you should be able to make invocations on other objects in your Java application, but make sure that it is thread-safe.
Related
I have a C shared library that is used from a Java application via JNI. I need to store some expensive-to-calculate data which will be valid for the lifespan of a JavaVM. I would like to store this in a static variable in C, so that it gets calculated exactly once.
Of course, this will fail if it is possible for my library to be used from multiple JavaVMs in the same process. My static values would only be valid in the first JavaVM. If my library is being loaded from Java via System.loadLibrary in a static block on a class, is it ever possible for said library to be used across multiple JavaVMs without having to completely unload my C shared library?
Yes. Most popular JVM implementations, in particular, HotSpot JVM and its derivatives, allow only one Java Virtual Machine per process.
In fact, an implementation allowing multiple VMs in one process, will not be compliant with the JNI specification, as the documentation to JNI_CreateJavaVM and JNI_GetCreatedJavaVMs explicitly says that
Creation of multiple VMs in a single process is not supported.
The android documentation for the java.lang.Runtime class makes multiple reference to the JVM, for example calling the freeMemory() method:
Returns the amount of free memory in the Java Virtual Machine.
Yet in recent versions of android there is no virtual machine. What exactly does this method, and other similar methods, return?
If I'm not mistaken, this is what gets call at the platform level from the Runtime::freememory() method: https://android.googlesource.com/platform/art/+/refs/tags/android-9.0.0_r51/openjdkjvm/OpenjdkJvm.cc#297 which then calls https://android.googlesource.com/platform/art/+/refs/tags/android-9.0.0_r51/runtime/gc/heap.h#548.
You can keep digging if you want to get to the very bottom of it, but it seems the ART is trying to provide a valid value to the calling app.
I am new to Java & JNI. This question maybe very newbe. I have C++ library and Java application which interns call the C++ function using JNI concepts.
As per my understanding, JVM loads the C++ dll/SO in JVM space before calling a native function call.
If my understanding on the JVM is correct on JNI. Can someone tell me which/who is going to execute the C++ library function which is loaded inside the JVM.
Let say for C++, there is standard dynamic linker-loader present to handling the dynamic execution part of the C++ and executes all the machine instructions.
In case of JVM loaded JNI Libs (in this case C++ libs), does JVM executes the those libs ? If so does it uses its memory to execute the native function?
Thanks in advance.
The Java language allows you to mark certain methods as native. The Java Native Interface allows you to link these Java methods to a function address in native code.
When you System.loadLibrary a library that contains native code, the JVM will do two things:
Look for specifically named functions such as Java_pkg_Cls_f_ILjava_lang_String_2 and link this to the function f in class pkg.Cls.
Call JNI_OnLoad, if it exists in the library. This can perform initialization and optionally link more native methods using registerNatives.
After this point, the native library indeed resides in the process' memory space like any other library (say, libcurl or libssl). When you actually call one of the native methods, the JVM will find the function address and use a native call instruction to jump into the function. The function will execute as part of the stack trace of that thread and will show up as such in both the JVM and native stack traces.
In more advanced cases, the library might spawn additional native threads. These work like regular threads in native code and are invisible to the JVM. If these threads need to talk to the JVM as well, the developer can attach them.
I have created a JNI wrapper with swig for a library. I use swig directors to call back into the JVM. Some of these callbacks occur on threads created within the native library. The first callback on a non JVM thread fails with a SIGSEGV which I could trace down to ignoring the negative return value (-1) of AttachCurrentThread and thus dereferencing a jenv pointer which is actually null. This happens in the swig generated code.
I have tried to call back into the JVM via the director classes from a thread that I created on the native side. This works fine. It does however not work from the thread created by the library I wrapped.
What can be possible reasons that AttachCurrentThread fails?
When a thread does not have sufficient stack space left AttachCurrentThread fails. Unfortunately the documentation of the Oracle JVM does not mention the minimum required stack space for AttachCurrentThread to work.
In my case the native library was optimized for embedded hardware and therefore creates threads generally with a stack size of 100000 bytes.
I'm working on a Java application that needs to communicate with a C application. The C application uses shared memory and mmap to communicate, and I need the Java application to have access to the same memory.
My first attempt involved using JNI calls to retrieve data from the shared memory, but the overhead of each JNI call killed performance, so I'd like a way to get access to that memory in Java and do the data retrieval on the Java side.
The idea I have is that I'd need do the following:
Use one JNI call to get the location of the shared memory location I need to attach to
Create a new FileChannel()
Use that FileChannel to create a MappedByteBuffer using map()
Is this the best way to do this? Also, I'm not sure how to actually create the FileChannel to point at the correct memory location.
Look into using ByteBuffer.allocateDirect. Apparently these buffers can be passed over the JNI layer to native code which can access the memory directly.
See this page (quoted below) for hints.
Now, not only can JNI code discover the address of the native memory space inside of a buffer created with ByteBuffer.allocateDirect() on the Java side, but it can allocate its own memory (with malloc(), for example) and then call back to the JVM to wrap that memory space in a new ByteBuffer object (the JNI method to do this is NewDirectByteBuffer()).
i would write a small C module mmaps the shared memory and used sockets to allow another application to see that memory (e.g. your Java app)
If you own both the C and Java application, they could just communicate through the console streams - ugly for binary data but possible. I would exchange the shared memory for a more message passing style - e.g. TCP/IP socket pair.
Btw, what kind of data is passed around and how large is it?
Couldn't you write a Java class with some native methods, write the native method implementation in C to do what you want with mmap. Then compile that into a native library and add it to your runtime using LD_LIBRARY_PATH. This'll enable you to make native C calls in Java without the JNI overhead (I think).
Some tutorials here: link
For example, you would write a Java class such as:
JMMap.java
public class JMMap {
public native void write(...)
}
Then run javah against the class file to produce something like:
JMMap.h
JNIEXPORT void JNICALL Java_JMMap_write(JNIEnv *, jobject);
Implement this in a .c file. Compile that to a library. Add it to the LD path, and then just call the Java function.
If you could save the data into a file in C, and then access the file from Java, that would be best. AFAIK you cannot point to memory in the way that you would like using Java.