Native开发过程中容易忽略的注意事项

发布时间 2023-03-29 07:43:30作者: 懒懒初阳

在进行native开发时,还需要注意以下事项:

  1. 不要在native方法中直接抛出Java异常。应该使用JNIEnv中提供的函数来创建和抛出Java异常。

  2. 不要在native方法中缓存JNIEnv指针,因为它可能会在运行时被释放或重载。

  3. 在native方法中访问Java对象时,需要使用JNI提供的函数来获取和操作Java对象,避免直接访问Java对象的内部成员。

  4. 注意本地库和Java代码的链接方式和加载顺序,避免出现库加载失败或符号冲突等问题。

  5. 在本地库中使用动态内存分配时,需要注意及时释放分配的内存,避免内存泄漏和程序崩溃。

以下是一些常见的native开发注意事项的具体示例:

  1. 不要在native方法中直接抛出Java异常

c++

JNIEXPORT void JNICALL
Java_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj) {
    jclass exceptionClass = env->FindClass("java/lang/Exception");
    env->ThrowNew(exceptionClass, "Native method exception");
    // 抛出异常后必须返回,否则代码将继续执行
    return;
}
  1. 不要在native方法中缓存JNIEnv指针

c++

JNIEXPORT void JNICALL
Java_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj) {
    jclass cls = env->GetObjectClass(obj);
    jmethodID methodID = env->GetMethodID(cls, "javaMethod", "()V");
    // 缓存JNIEnv指针,容易出现问题
    JNIEnv *cachedEnv = env;
    cachedEnv->CallVoidMethod(obj, methodID);
    // 应该每次都重新获取JNIEnv指针
    env->CallVoidMethod(obj, methodID);
    return;
}
  1. 在native方法中访问Java对象时,使用JNI提供的函数来获取和操作Java对象

c++

JNIEXPORT void JNICALL
Java_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj, jobject jobj) {
    // 直接访问Java对象的内部成员是不安全的
    jclass cls = env->GetObjectClass(jobj);
    jfieldID fieldID = env->GetFieldID(cls, "field", "Ljava/lang/String;");
    jstring str = (jstring)env->GetObjectField(jobj, fieldID);
    // 应该使用JNI函数来获取和操作Java对象
    jclass stringCls = env->FindClass("java/lang/String");
    jmethodID lengthID = env->GetMethodID(stringCls, "length", "()I");
    int length = env->CallIntMethod(str, lengthID);
    return;
}
  1. 注意本地库和Java代码的链接方式和加载顺序

在Android.mk或CMakeLists.txt中设置链接选项和库依赖,例如:

makefile

LOCAL_LDLIBS := -llog -landroid
LOCAL_SHARED_LIBRARIES := libfoo

在Java代码中加载本地库,例如:

java

static {
    System.loadLibrary("mylib");
}
  1. 在本地库中使用动态内存分配时,注意及时释放分配的内存

c++

JNIEXPORT jbyteArray JNICALL
Java_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj, jint size) {
    jbyte *buffer = new jbyte[size];
    // 使用完毕后必须释放内存,避免内存泄漏
    jbyteArray result = env->NewByteArray(size);
    env->SetByteArrayRegion(result, 0, size, buffer);
    delete[] buffer;
    return result;
}