tags:

views:

587

answers:

5

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:

  1. Use one JNI call to get the location of the shared memory location I need to attach to
  2. Create a new FileChannel()
  3. 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.

A: 

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.

AlbertoPL
A: 

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?

kd304
I'm not exactly sure the size; could be roughly 800Mb to over a Gb. Unfortunately, I don't have the luxury of modifying the C application.
Brian
Create a new C application that wraps the original C application. Once you do that, either kd304's solution or AlbertoPL's solution should be possible.
NamshubWriter
Is it always necessary to move the entire data between apps?
kd304
The data doesn't need to be moved at all, I just need to be able to read from the shared memory used by the C application.
Brian
+1  A: 

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)

KitsuneYMG
A: 

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 funtion.

omerkudat
+3  A: 

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()).

Steve Reed
this is going to be as close to the metal as you can get in Java. Unfortunately, the ByteBuffer is still going to need to pull info across the VM boundary. It may be instructive to take a look at how the JDK implements Deflator - http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/Deflater.html
Kevin Day