Java字符串对象创建:Java和;在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> (下面给出的每个文件中都需要部分代码)

我在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> (下面给出的每个文件中都需要部分代码)

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)的位置上,我也尝试了以下方法

  • StringBuilder strObj=新的StringBuilder(内部容量=100)
  • Integer intObj=新整数(int值=100)
    但在纯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一次并不重要