gpt4 book ai didi

android-ndk - 缓存JNI对象和线程安全性(在Android中)

转载 作者:行者123 更新时间:2023-12-04 02:38:13 26 4
gpt4 key购买 nike

我正在使用 native 线程(pthread)编写C++应用程序,并且需要调用一些Java方法等。我不确定哪些JNI对象可以安全地缓存,即存储在我的C++对象中以便以后使用,可能/可能是不同的线程。我确实知道,如果我的类的方法可以由不同的线程调用,则我不必缓存JNIEnv,而应该缓存JavaVM并通过附加当前线程来获取JNIEnv。但这是否还意味着我无法缓存从JNIEnv获得的任何内容?我需要使用通过以下JNIEnv方法获得的对象:

FindClass,GetMethodID,NewObject,NewGlobalRef

它们在线程间保持有效,还是每次都必须获取新的?如果是后者,是否有办法在一个 native 线程中创建对象并能够在其他线程中访问同一对象?

最佳答案

FindClassGetMethodIDGetFieldID这样的JNI方法是昂贵的操作,可以保证在JVM的整个生命周期内产生相同的结果。由于这些操作很耗时,因此明智的做法是将结果存储在某个地方,以便稍后在 native 端重用(这是缓存)。

JNI缓存仅处理这些JNI函数调用。如果要缓存任何其他C++或Java对象,这是一个不同的主题。 (只是要清楚)。

缓存的类,方法和字段不依赖于它们从中检索到的线程,因此它们在不同的线程之间有效。在使用Set<type>FieldGet<type>Field获取或设置某个对象的字段时,至多您必须执行线程安全操作。

由于FindClass返回对类对象的本地引用,因此您必须将其转换为全局引用,以确保在检索它的函数结束后可以重用它。您可以使用NewGlobalReference实现此目的:

jclass tmp_double_Class = env->FindClass( "java/lang/Double" ); // Check for exceptions!
double_Class = static_cast<jclass>( env->NewGlobalRef( tmp_double_Class ) );
if( double_Class == NULL )
return;
env->DeleteLocalRef( tmp_double_Class );

这里有一个所有“JNI缓存”主题的示例:

MyJni.cpp:

// Just a shortcut for checking for exceptions
#define CHECK_JNI_EXCEPTION( JNIenv ) \
if( JNIenv->ExceptionCheck() )\
{\
JNIenv->ExceptionClear();\
return JNI_FALSE;\
}\
\

// Global variables
jclass point_Class;
jmethodID point_ctor_Method;
jfieldID point_x_Field;
jfieldID point_y_Field;

JNIEXPORT jboolean JNICALL Java_com_company_package_MyClass_nativeInit( JNIEnv * env,
jclass clazz )
{
// Cache java.lang.Double class, methods and fields
jclass tmp_point_Class = env->FindClass( "android/graphics/Point" );
CHECK_JNI_EXCEPTION( env )
point_Class = static_cast<jclass>( env->NewGlobalRef( tmp_point_Class ) );
if( point_Class == NULL )
return JNI_FALSE;
env->DeleteLocalRef( tmp_point_Class );
point_ctor_Method = env->GetMethodID( point_Class, "<init>", "(II)V" );
CHECK_JNI_EXCEPTION( env )
point_x_Field = env->GetFieldID( point_Class, "x", "I" );
CHECK_JNI_EXCEPTION( env )
point_y_Field = env->GetFieldID( point_Class, "y", "I" );
CHECK_JNI_EXCEPTION( env )
return JNI_TRUE;
}

MyJni.java:

package com.company.package;

class MyClass {
// ... All java code here ...

// Trigger JNI Caching (could be also done using JNI_OnLoad...)
private static native void nativeInit();

static {
System.loadLibrary( "mylib" );
nativeInit(); // should check the result
}
}

玩得开心 ;)

关于android-ndk - 缓存JNI对象和线程安全性(在Android中),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13893089/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com