Java字符串对象创建:Java和;在JNI
我在java和jni之间做了一个时差测试,创建了一个字符串对象(newstring(“somestring”);)1亿次。当通过Java代码进行测试时,执行大约需要1秒。但是当通过Jni代码测试它时,大约需要31秒 对于JNI部分,我需要更改JNI代码设计还是需要添加额外的编译器选项来提高执行速度 环境:Java字符串对象创建:Java和;在JNI,java,java-native-interface,Java,Java Native Interface,我在java和jni之间做了一个时差测试,创建了一个字符串对象(newstring(“somestring”);)1亿次。当通过Java代码进行测试时,执行大约需要1秒。但是当通过Jni代码测试它时,大约需要31秒 对于JNI部分,我需要更改JNI代码设计还是需要添加额外的编译器选项来提高执行速度 环境: Mingw(32) Windows 8.1(64) Java 1.8(32) C++编译器选项:-共享-M32 -WL,添加STDCALL别名< /P> (下面给出的每个文件中都需要部分代码)
Mingw(32)
Windows 8.1(64)
Java 1.8(32)
C++编译器选项:-共享-M32 -WL,添加STDCALL别名< /P> (下面给出的每个文件中都需要部分代码) C++文件:
class javaString {
jclass cls;
jmethodID method;
jstring strNew;
jobject obj;
public:
javaString() {
}
void myInit(JNIEnv *env) {
jclass cls1 = env-> FindClass("java/lang/String");
cls = (jclass) env->NewGlobalRef(cls1);
env->DeleteLocalRef(cls1);
method = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");
}
void myCall(JNIEnv *env, long lng) {
strNew = env->NewStringUTF("Apple");
for (long i = 0; i < lng; i++) {
obj = env->NewObject(cls, method, strNew);
env->DeleteLocalRef(obj);
}
env->DeleteLocalRef(strNew);
env->DeleteGlobalRef(cls);
}
};
javaString objStr;
JNIEXPORT void JNICALL Java_c_wrapperforjavaclass_clsNative_fnInit
(JNIEnv *env, jobject obj) {
objStr.myInit(env);
}
JNIEXPORT void JNICALL Java_c_wrapperforjavaclass_clsNative_fnCall
(JNIEnv *env, jobject obj, jint a) {
long lng = a;
objStr.myCall(env, lng);
}
在string对象(java/lang/string)的位置上,我也尝试了以下方法
但在纯Java中,优化编译器可以“理解”创建字符串是为了立即销毁,并且合法地什么也不做。当涉及JNI时,Java和C都无法避免执行每个步骤。如下更改代码执行时间从31秒更改为9秒左右 C++文件:
public class clsNative {
public native void fnInit();
public native void fnCall(int a);
public void fnProcess2(int a){
for(int i=0;i<a;i++){
String str = new String("Apple");
str=null;
}
}
}
clsNative a = new clsNative();
boolean blnJNITest=true;
String s1, s2;
s1 = Calendar.getInstance().getTime().toLocaleString();
int ii = 100000000; //100 million
if (blnJNITest) {
a.fnInit();
a.fnCall(ii);
} else {
a.fnProcess2(ii);
}
s2 = Calendar.getInstance().getTime().toLocaleString();
System.out.println(s1);
System.out.println(s2);
void myInit(JNIEnv *env) {
jclass cls1 = env-> FindClass("java/lang/String");
cls = (jclass) env->NewGlobalRef(cls1);
env->DeleteLocalRef(cls1);
method = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");
}
void myCall(JNIEnv *env, long lng) {
strNew = env->NewStringUTF("Apple");
jobjectArray objarr = env->NewObjectArray(lng, cls,strNew);
if (objarr != NULL) {
cout << "Array constructed" << endl;
for (long i = 0; i < lng; i++) {
obj = env->GetObjectArrayElement(objarr, i);
env->DeleteLocalRef(obj);
}
} else {
cout << "Array construction failed" << endl;
}
env->DeleteLocalRef(strNew);
env->DeleteLocalRef(objarr); /*Not sure is this 2nd line need*/
env->DeleteGlobalRef(cls);
}
void myInit(JNIEnv*env){
jclass cls1=env->FindClass(“java/lang/String”);
cls=(jclass)env->NewGlobalRef(cls1);
env->DeleteLocalRef(cls1);
method=env->GetMethodID(cls,“,”(Ljava/lang/String;)V);
}
无效myCall(JNIEnv*env,长lng){
strNew=env->NewStringUTF(“苹果”);
jobjectArray objarr=env->NewObjectArray(lng、cls、strNew);
if(objarr!=NULL){
cout DeleteLocalRef(obj);
}
}否则{
cout DeleteLocalRef(objarr);/*不确定是否需要第二行*/
环境->删除全局参考(cls);
}
Java文件(测试):
int ii = 10000000; //10 million
if (blnJNITest) {
for(int i=0;i<10;i++){ //call 10 times
a.fnInit();
a.fnCall(ii);
}
}
int ii=10000000//1000万
如果(blnJNITest){
例如(int i=0;i您的示例清楚地表明,在字节码和本机代码之间转换是一个相当昂贵的操作,因此我建议仅在Java中无法本机完成的事情(如低级设备或操作系统交互)上使用JNI,或者长时间的计算,其中产生的转换代价会被性能提升所抵消,例如。您在Java代码和JNI代码中做的事情并不相同。无论如何,当您使用NewStringUTF
JNI API“创建”字符串(与DeleteLocalRef
结合使用)时会发生什么?@manuell.Thank.处理了fncall方法中的DeleteLocalRef。您的代码无效。您不应该在JNI调用之间存储JNIEnv*
,也不应该对每个对象多次调用构造函数。您获得的结果没有任何意义或相关性。@EJP,谢谢。代码修改为在JNI调用之间不存储JNIEnv*。“优化编译器可以理解创建字符串是为了立即销毁“你的意思是字符串是不可变的吗?不,我的意思是Java确切地知道字符串范围只有一行。在中释放类全局引用是错误的loop@AlexCohn,仅在循环外部发生全局引用释放。每次在Jni调用myInit()中创建并在myCall()结束时释放。在这里,全局引用(jclass)作为多个Jni调用之间的缓存。或者您的意思是不应该频繁创建和删除全局引用(具有最小的时间间隔)?好的,每10^7一次并不重要