/**
* example-01: GetStringUTFChars()
*
* 代码出自《The Java Native Interface Programmer’s Guide and Specification》
* 运行平台:Windows XP
*/
/**
* The example program, Prompt.java , contains a
* native method that prints a string, waits for user input, and then returns the line
* that the user has typed in.
*/
// Prompt.java
public class Prompt
{
// native method that prints a prompt and reads a line
private native String getLine(String prompt);
public static void main(String args[])
{
Prompt p = new Prompt();
String temp = new String("Type a line: ");
String input = p.getLine(temp);
System.out.println("User typed: " + input);
System.out.println(temp);
}
static
{
System.loadLibrary("Prompt");
}
}
/* command
javac Prompt.java
javah Prompt
get a file: Prompt.h
*/
#include "Prompt.h"
#include <stdio.h>
#include <string.h>
JNIEXPORT jstring JNICALL Java_Prompt_getLine (JNIEnv *env, jobject obj, jstring prompt)
{
char buf[128];
const jbyte *str;
jboolean isCp;
str = (*env)->GetStringUTFChars(env, prompt, &isCp);
if (str == NULL) {
return NULL; /* OutOfMemoryError already thrown */
}
if(isCp == JNI_TRUE)
{
strcpy(str,"12345");
printf("str: %d\n", str);
printf("prompt: %d\n", prompt);
}
printf("%s", str);
(*env)->ReleaseStringUTFChars(env, prompt, str);
/* We assume here that the user does not type more than
* 127 characters */
scanf("%s", buf);
return (*env)->NewStringUTF(env, buf);
}
/*
set java_inc=E:\FILES\java\jdk1.6.0_29\include
cl -I%java_inc% -I%java_inc%\win32 -LD Prompt.c -FePrompt.dll
*/
/* output
str: 45913800
prompt: 9698564
12345kjkjkjkjk
User typed: kjkjkjkjk
Type a line:
the output demonstrates that String instance temp did not changed, and isCopy is JNI_TRUE
*/
/** example-2: GetIntArrayElements()
*
*/
// TestJNI.java
public class TestJNI
{
public native void intArray(int[] ii);
public static void main(String[] args)
{
System.loadLibrary("TestJNI");
TestJNI jni = new TestJNI();
int[] ii = new int[4];
for(int i = 0; i < ii.length; i++)
{
ii[i] = i;
}
jni.intArray(ii);
for(int i = 0; i < ii.length; i++)
{
System.out.println(ii[i]);
}
}
}
// TestJNI.c
#include "TestJNI.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_TestJNI_intArray(JNIEnv *env, jobject obj, jintArray intArr)
{
jboolean isCp;
int i;
jsize len = (*env)->GetArrayLength(env, intArr);
jint *arr = (*env)->GetIntArrayElements(env, intArr, &isCp);
if(isCp == JNI_TRUE)
{
printf("isCopy: JNI_TRUE\n");
printf("arr: %d\n", arr);
printf("intArr: %d\n", intArr);
}
for(i = 0; i < len; i++)
{
arr[i] = 100 + i;
}
(*env)->ReleaseIntArrayElements(env, intArr, arr, 0);
}
/* output
isCopy: JNI_TRUE
arr: 45914656
intArr: 9698564
100
101
102
103
the output shows that ii has been changed, but isCopy is JNI_TRUE
*/
问题:
example-1中,isCopy 被设置为 JNI_TRUE,说明重新分配了内存,修改str(str = "12345")不影响prompt(prompt is still "Type a line: "),这是合乎官方文档及书中说明的
example-2中,isCopy 被设置为 JNI_TRUE,说明重新分配了内存,但arr和intArr都被修改了,这是不合乎官方文档及书中说明的
【参考资料】
The Java Native Interface Programmer’s Guide and Specification, chapter 3 Basic Types, Strings, and Arrays
docs/technotes/guides/jni/spec/functions.html
问题解决:
If necessary, this function(Release<PrimitiveType>ArrayElements) copies back all changes made to elems to the original array.
(from: docs/technotes/guides/jni/spec/functions.html#wp17314 or http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html#wp17314)
(*env)->ReleaseIntArrayElements(env, intArr, arr, 0);
void Release<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array, NativeType *elems, jint mode);
mode = 0 means "copy back the content and free the elems buffer"
ReleaseIntArrayElements enables the JNI to copy back and free body if it is a copy of the original Java array, or "unpin" the Java array if it has been pinned in memory.
Forgetting to call ReleaseIntArrayElements results in either pinning the array for an extended period of time, or not being able to reclaim the memory used to store the nonmovable copy of the array.
下面是 mode = JNI_ABORT 的运行结果:
#include "TestJNI.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_TestJNI_intArray(JNIEnv *env, jobject obj, jintArray intArr)
{
jboolean isCp;
int i;
jsize len = (*env)->GetArrayLength(env, intArr);
jint *arr = (*env)->GetIntArrayElements(env, intArr, &isCp);
if(isCp == JNI_TRUE)
{
printf("isCopy: JNI_TRUE\n");
printf("arr: %d\n", arr);
printf("intArr: %d\n", intArr);
}
for(i = 0; i < len; i++)
{
arr[i] = 100 + i;
}
(*env)->ReleaseIntArrayElements(env, intArr, arr, JNI_ABORT); // mode = JNI_ABORT
}
/* output
isCopy: JNI_TRUE
arr: 45914656
intArr: 9698564
0
1
2
3
*/
关于isCopy的问题:
【参考资料】
The Java Native Interface Programmer’s Guide and Specification, chapter 3 Basic Types, Strings, and Arrays(主)
docs/technotes/guides/jni/spec/functions.html