返回

JNI 局部引用与全局引用:深入浅出

Android

JNI 中的引用类型:本地与 Java 内存交互的关键

理解引用类型的基本概念

在 Java 虚拟机 (JVM) 与 Java 本机接口 (JNI) 之间的交互中,传递数据涉及不同内存空间之间的转换。对于引用类型对象(如字符串或数组),有两种类型的引用可以发挥作用:局部引用和全局引用。

局部引用:短暂但高效的访问

局部引用是临时引用,在 JNI 方法调用期间创建并使用。它们在方法调用结束时自动释放。这意味着 Java 对象在 JNI 方法中只能通过局部引用访问。使用局部引用的好处是,由于它们自动释放,因此可以避免内存泄漏。

示例:局部引用的使用

JNIEnv* env = ...;
jobject obj = env->GetObjectField(env->FindClass(...), ...);
// 使用局部引用访问对象...
env->DeleteLocalRef(obj);

在上面的示例中,局部引用 obj 用于在 JNI 方法中访问 Java 对象。方法调用结束后,obj 将自动释放。

全局引用:持久的访问,但需要谨慎

全局引用是持久的引用,在 JNI 方法调用期间创建并使用。它们不会在方法调用结束时自动释放。这意味着 Java 对象可以在 JNI 方法外部通过全局引用访问。使用全局引用的好处是,它允许在 JNI 方法外部访问 Java 对象。

示例:全局引用的使用

JNIEnv* env = ...;
jobject obj = env->GetObjectField(env->FindClass(...), ...);
jobject globalRef = env->NewGlobalRef(obj);
// 在 JNI 方法外部使用全局引用访问对象...
env->DeleteGlobalRef(globalRef);

在上面的示例中,全局引用 globalRef 用于在 JNI 方法外部访问 Java 对象。全局引用必须在不再需要时显式释放,以避免内存泄漏。

选择合适的引用类型:谨慎使用全局引用

选择正确的引用类型对于避免内存泄漏至关重要。一般来说,局部引用应优先使用,因为它们在方法调用结束时自动释放。全局引用仅在需要在 JNI 方法外部访问 Java 对象时使用。

局部引用与全局引用的使用准则

  • 局部引用: 在 JNI 方法内部访问 Java 对象。
  • 全局引用: 在 JNI 方法外部访问 Java 对象。
  • 优先使用局部引用: 当不需要在 JNI 方法外部访问 Java 对象时,请优先使用局部引用。
  • 显式释放全局引用: 在不再需要时,请显式释放全局引用。

附加提示:确保健壮的 JNI 代码

  • 除了局部引用和全局引用之外,JNI 还提供弱全局引用,它可以防止 Java 对象被垃圾回收。
  • JNI 引用的管理至关重要,因为不当管理可能会导致内存泄漏和应用程序崩溃。
  • 建议使用 JNIRefLib 等工具来帮助管理 JNI 引用。

常见问题解答

1. 什么时候应该使用局部引用?
当仅在 JNI 方法内部需要访问 Java 对象时,应使用局部引用。

2. 什么时候应该使用全局引用?
当需要在 JNI 方法外部访问 Java 对象时,应使用全局引用。

3. 局部引用和全局引用的主要区别是什么?
局部引用在方法调用结束时自动释放,而全局引用需要显式释放。

4. 如何避免 JNI 中的内存泄漏?
通过正确使用局部引用和全局引用,并显式释放不再需要的全局引用,可以避免内存泄漏。

5. JNI 中的引用类型如何影响性能?
局部引用比全局引用更有效,因为它们自动释放,避免了手动管理的开销。