JNI: Get/ReleaseStringUTFChars和Get/ReleaseIntArrayElements的区别,isCopy是否重新分配内存的问题

本文探讨JNI中处理字符串和数组的不同方法,重点关注Get/ReleaseStringUTFChars与Get/ReleaseIntArrayElements的区别。通过分析,揭示isCopy参数在内存管理中的作用,特别是如何避免引发OutOfMemoryError。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
 * 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.

(from: http://www.science.uva.nl/ict/ossdocs/java/tutorial/native1.1/implementing/array.html)

下面是 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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值