Calling DeleteLocalRef in java native interface - java

I'm returning a jstring from a JNI method. I delete the local reference to it before returning the value.
JNIEXPORT jstring JNICALL TestJNIMethod( JNIEnv* env, jclass )
{
jstring test_string = env->NewStringUTF( "test_string_value" );
env->DeleteLocalRef( test_string );
return test_string;
}
Would the calling JAVA method be still able to access the returned jstring or would the Garbage collector cleanup the memory?

No it will not, however your code will work on Android versions earlier than ICS. From ICS on this code will correctly fail.
In general you don't need to delete local references yourself, once the JNI function returns to Java the references will get GC'd.
The exception to that rule is if you create a lot of them, perhaps in a loop. Then it is possible to fill the local reference table. See IBM: Overview of JNI object references.
You should read JNI Local Reference Changes in ICS. Even if you are not writing for Android, it still identifies many common mistakes.

Related

how to modify the value of a primitive data passed to a C++ routine using Java and JNI?

Can I pass a primitive from Java to my C++ function using JNI function calls and modify its value in the C++ function ?
So far, I have seen examples of returning jstring,jint,jboolean etc, which I do not want to do. The other option that I know about is to get the ID of the primitive variable within C++ and set its value.
For Example :
JNIEXPORT void JNICALL Java_myFunction
(JNIEnv *, jobject obj, jboolean retJava)
Here i am passing boolean from java and want to change it in C++ depending on my computation without return statement.
Unfortunately you can not do this with JNI.
You can hack it with using boxed types (see an example here) but it is strongly discouraged, as it can break all kinds of things easily (as to what exactly, see the comments in the linked question).

Android JNI C++ Code always get "same" jobject value for 2 different SurfaceView object

In Android JAVA code:
public native int addRenderer(int channel, Object glSurface);
Context context = getApplicationContext();
SurfaceView svRemotePartyA = new SurfaceView(context);
SurfaceView svRemotePartyB = new SurfaceView(context);
addRenderer(0, svRemotePartyA);
addRenderer(1, svRemotePartyB);
In Android JNI C++ code:
extern "C" jint JNIEXPORT JNICALL Java_addRenderer(
JNIEnv* jni,
jobject j_vie,
jint channel,
jobject surface) {
LOG(LS_INFO) << "Java_addRenderer(): surface=" << surface;
// some processing
}
When I run the programme, I always read the following log! both SurfaceView object have same value in JNI C++ code log output:
(render_manager.cc:175): Java_addRenderer(): surface==0xbeed6120
(render_manager.cc:175): Java_addRenderer(): surface==0xbeed6120
What's the problem?
You look at local references, which should never be used beyond the context of the same JNI method. If you get a global reference for this jobject, you will get 2 different ones.
You should not attempt to associate a meaning with the specific bit pattern of a JNI reference.
For example, in Dalvik, local references are just indices into a table on the stack. If you make the same call several times with different objects, you will see the same "value" for the reference each time, because the object reference is sitting in the same place in the local reference table.
(It's not quite that simple -- Dalvik actually tucked a trivial serial number into the reference to make it easier to tell when a local ref was used after it had been reclaimed -- but you get the idea.)
Similarly, you cannot make the assumption about global references. If you create two global references to the same object, it's very likely that those references will have different 32-bit values.
Every VM is different. Old (pre-ICS) versions of Dalvik actually passed raw pointers around, and you could compare the reference values to determine if two objects were the same. The switch to indirect references required fixing up a few things.
If you want to tell if two objects are the same, you need to have references to both, and use the JNI IsSameObject() function.
Some additional background is here.

Return MPI::Request[] type from JNI and access elements of Request in Java

I'm looking to return an MPI::Request[] type from a native C++ function to Java (via JNI) and subsequently access elements in the MPI::Request[] array from the Java side.
JNIEXPORT jobjectArray JNICALL Java_mpiJNI_mpiTEST(JNIEnv *env, jobject obj) {
MPI::Request req[8];
return req; // Error: Can't convert req to jobjectArray type
}
The only return types I know of that would be close are jobjectArrays and this does not work. Java doesn't know what an MPI::Request[] type is.
I've not wanted to use things like MPJ or MPIJava because I don't know that there is much support for future MPI work in Java and want to have code that will persist through many cluster updates and configurations. If someone knows more about this matter I would be interested to hear more.
You need to return a JNI type of type jobjectArray. JNI will not convert that req pointer to a jobjectArray for you. Also note that how java lays out object arrays and
First off, you are allocating an array on the C++ stack. This is not a persistent memory and thus req pointer will be garbage when your JNI method returns. So if you want to preserve or allocate the native array storage, you will need to allocate the memory with 'new' and have a persistent pointer to your array.
What I would suggest, is that instead of returning and creating a object array, you return a single "pointer" value back to java to the begining of the the Request array, just like you would do in C++.
In order to preserve a native pointer inside a Java object, the typical trick is to convert the pointer to a java 'long' primitive type, which is long enough to hold the actual native address on most platforms. The store the return 'long' in your java class as field.
Next time you need access to the native MPI::Request array, you make a call to a native java method and pass it the address value stored as 'long' and in you corresponding JNI method, convert the JNI jlong parameter back to a pointer and typecast it to MPI::Request *req and thus you will have successfully created the request in your java/jni method, returned it, and stored inside a java class and then again used it natively in a second method where you can make the C++ calls to create/send those requests and so on.
Lastly, since you dynamically allocated the native memory for the MPI::Result[], remember to make another java native method that will again convert the long value to a pointer and release the memory with C++ delete statement, after you no longer need that array. Otherwise you will have a memory leak.
So here is how I would rewrite your JNI method:
JNIEXPORT jlong JNICALL Java_mpiJNI_mpiTEST(JNIEnv *env, jobject obj) {
MPI::Request *req = new MPI::Request[8]; // Don't forget to release memory leater
uintptr_t storage = (uintptr_t)ptr
return (jlong) storage;
}

Correct usage of DeleteLocalRef in JNI

Here is the sample jni method where I create a string and return it to the calling java method:
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
char test[100];
sprintf(test, "Test%03d.txt", rand()/100);
jstring returnVal = (*env)->NewStringUTF(env, test);
(*env)->DeleteLocalRef(env,returnVal);
return returnVal;
}
I was expecting the jstring to be invalid in the calling java method since I deleted the local reference. But the reference is still valid. I explicitly called System.gc() to see whether the GC clears it, but it didn't happen.
According to this: http://android-developers.blogspot.com/2011/11/jni-local-reference-changes-in-ics.html
"Bug: Calling DeleteLocalRef() and continuing to use the deleted reference
It shouldn’t need to be said that it’s illegal to continue to use a reference after calling DeleteLocalRef() on it, but because it used to work, so you may have made this mistake and not realized. The usual pattern seems to be where native code has a long-running loop, and developers try to clean up every single local reference as they go to avoid hitting the local reference limit, but they accidentally also delete the reference they want to use as a return value!
The fix is trivial: don’t call DeleteLocalRef() on a reference you’re going to use (where “use” includes “return”)."
I am little confused about the inconsistency.
What SDK level are you targeting? If you target 13 or lower (pre ICS) then you get the old JNI behaviour and this code should work (though it's still technically incorrect)
If you target 14 (ICS) or higher then the code shown will fail with the giveaway error:
memory map fault addr deadd00d
Note, the code will also work if you target SDK 14+, but run the app on an earlier version of Android

Java type and Native type [duplicate]

I need to call external DLL library function from Java code. I use Netbeans 7.2.
My dll's functions are:
Boolean isValid(string word)
List<String> getWords(String word)
I'm following this example. But I don't know how declare my dll functions.
And I found another link. But it doesn't work for me.
I stumbled upon the same problem of "calling DLL from Java" and first was frustrated about the complexity. Yet, there is an elegant solution (might also be interesting for the people over there in the processing.org habitat..)
Given the rather "general" form of the question (maybe, downrating is not justified for that), I suppose, a rather easy-going solution would be indicated. In other words, a solution that avoids messing aronud with header files, extra conversions, etc., just as the source code is not necessarily available.
My recommendation for that would be JNA (https://github.com/twall/jna), which basically is a simplifying wrapper around JNI. It works great, type mapping is straightforward (e.g. pchar = lpcstr buffer -> string), though I am using it only towards Windows DLLs and my own C-style DLLs created using Delphi-Pascal. The only thing to consider is that return values should be exported through functions rather than "out" flagged reference variables.
The question already points to a linked source that provides an example for that (so, answers around JNI may be misplaced here). Note that the link I provided also contains axamples for the transfer of arrays and pointers.
You will need to use the Java Native Interface (JNI), which is a set of C/C++ functions that allow native code to interface with java code (i.e. receiving parameters from java function calls, returning results, etc). Write a wrapper C library that receive JNI calls and then call your external library.
For instance, the following function invokes a method updateHandlers on a native object (that is stored as long in the Java side).
class MyImpl {
void updateHandlers(JNIEnv *env) {
this->contentHandler = ....;
}
}
JNIEXPORT void JNICALL Java_package_Classname_updateHandlers0
(JNIEnv *env, jobject obj, jlong ptr)
{
((MyImpl*)ptr)->updateHandlers(env);
}
The corresponding declarations in package.ClassName are:
private long ptr; //assigned from JNI
public void updateHandlers() {
if (ptr==0) throw new NullPointerException();
updateHandlers0(ptr);
}
private native void updateHandlers0(long ptr);
static {
try {
/*try preloading the library external.dll*/
System.loadLibrary("external");
} catch (UnsatisfiedLinkError e) {
/*library will be resolved when loading myjni*/
}
System.loadLibrary("myjni"); //load myjni.dll
}
I did write some time ago sample tutorial, maybe it will help.
http://wendro.blogspot.com/2010/03/jni-example-eclipse-dev-cpp.html
You declare your native functions in java (native private ...) with the signature that you need; then run javah (a tool that is provided with the JDK) in order to generate the native headers. A List<String> (actually a List, because of type erasure) is a jobject in native code.
The corresponding C method, would be:
JNIEXPORT jobject JNICALL package_Classname_getWords(JNIEnv *env, jobject jobj, jstring word)
I think it would be easier to return an array of strings jobjectArray, and instantiate the List in java from the returned values. See this example.

Categories

Resources