Java 字符串对象创建:Java 和 JNI 中的执行时间不同

Java String Object creation : Execution time difference in both Java & in JNI

我做了一个java和jni的时间差测试,创建一个字符串对象(new String("some string");)一亿次。当通过 Java 代码测试时,执行大约需要 1 秒。但是当通过 Jni 代码测试它时,它花费了大约 31 秒。

对于JNI部分,我是否需要更改jni代码设计或需要添加额外的编译器选项来提高执行速度?

环境:
明威 (32)
Windows 8.1 (64)
Java1.8 (32)
C++ 编译器选项:-shared -m32 -Wl,--add-stdcall-alias

(下面给出的每个文件中需要部分代码)

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);
}

Java 文件:

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;
        }
    }
}

Java 文件(测试):

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);

代替字符串对象(java/lang/String),我也尝试了下面的方法

  1. StringBuilder strObj = New StringBuilder(int capacity = 100);
  2. 整数 intObj = 新整数(int 值 = 100);

在所有情况下,它花费的时间都差不多。

但在纯 Java 中,优化编译器可以 "understand" 创建的字符串立即被销毁,合法地不做任何事情。当涉及到JNI时,Java和C都不可能避免执行每一步。

如下更改代码,执行时间从 31 秒更改为大约 9 秒。

C++ 文件:

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);
}

Java 文件(测试):

    int ii = 10000000; //10 million
    if (blnJNITest) {
        for(int i=0;i<10;i++){ //call 10 times
            a.fnInit();
            a.fnCall(ii);
        }
    }