在性能路径中正确使用 JNI DetachCurrentThread
Properly using JNI DetachCurrentThread in performance paths
我正在编写一个多线程C++程序,它使用JNI与Java代码进行通信。根据设计,以下方法(run(((由线程运行,运行一次后,本机线程可能会切换。(循环式线程分配(
bool JavaModule::run()
{
initObjects();
/*Attaching to the current thread
*and checking for JVM exceptions
*for each run
*/
Interpreter::getEnv()->CallObjectMethod(objid, msgid, NULL);
if (Interpreter::getEnv()->ExceptionCheck())
{
getLogger().error("ERR: JVM Exception occurred when running the script");
return false;
}
//Detaching from the current thread
//There is a performance hit when detaching the Environment each time
Interpreter::detachEnv();
return true;
}
此调用位于程序的性能路径中,如果我尝试从当前线程附加和分离环境,则会出现很大的性能问题。附件发生在 getEnv(( 中,如下所示。
static JNIEnv* Interpreter::getEnv()
{
JNIEnv *env;
int status = jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (status < 0)
{
status = jvm->AttachCurrentThread((void**)&env, NULL);
if (status < 0)
{
return nullptr;
}
}
return env;
}
JVM 是一个定义为 static JavaVM* jvm;
分离代码如下所示。
static bool Interpreter::detachEnv()
{
if (jvm->DetachCurrentThread() == JNI_OK)
{
return true;
}
return false;
}
在这个代码级别,它不知道线程,在线程创建级别,它对JVM一无所知。
我的问题是,在不影响性能的情况下安全地分离线程的好解决方案是什么?
最好的解决方案是只附加到线程一次,让它运行它的过程,并在线程存在时自动与线程本地存储(C++ 11 或 ighter(分离。JVM可以附加并保持在多个线程上,因此无需继续连接和分离。下面是有关如何实现此目的的示例代码:
JNIEnv* JNIThreadHelper::GetJniEnv() {
// This method might have been called from a different thread than the one that created
// this handler. Check to make sure that the JNI is attached and if not attach it to the
// new thread.
// double check it's all ok
int nEnvStat = m_pJvm->GetEnv(reinterpret_cast<void**>(&m_pJniEnv), JNI_VERSION_1_6);
if (nEnvStat == JNI_EDETACHED) {
std::cout << "GetEnv: not attached. Attempting to attach" << std::endl;
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6; // choose your JNI version
args.name = NULL; // you might want to give the java thread a name
args.group = NULL; // you might want to assign the java thread to a ThreadGroup
if (m_pJvm->AttachCurrentThread(&m_pJniEnv, &args) != 0) {
std::cout << "Failed to attach" << std::endl;
return nullptr;
}
thread_local struct DetachJniOnExit {
~DetachJniOnExit() {
m_pJvm->DetachCurrentThread();
}
};
m_bIsAttachedOnAThread = true;
}
else if (nEnvStat == JNI_OK) {
//
}
else if (nEnvStat == JNI_EVERSION) {
std::cout << "GetEnv: version not supported" << std::endl;
return nullptr;
}
return m_pJniEnv;
}
不要将
性能关键线程附加或分离到 jvm。JVM需要与垃圾收集器同步,垃圾回收器是一个庞大的单线程关键部分。
如果您需要一个性能关键线程来与 jvm 通信,则需要使用某种异步消息传递来完成。
您也可以在线程创建和连接时附加和分离线程,但您仍然必须在其他方法中与 gc 同步。
相关文章:
- 通过JNI传递数据数组的最快方法是什么
- 为 NewObjectA() 函数创建 jvalues 的参数数组时出错 - JNI Invocation API
- 将 C# DLL 导入 C++ 以用于 JNI
- 用C++包装 Java 库 (JNI)
- 如何通过 JNI 将 C 字符串表情符号传递给 Java
- JNI从Android调用C++方法
- JVM 如何执行 JNI
- React Native (Android):无法通过 JNI 在 jobject 中返回字符串
- 如何将字符串数组返回到 java JNI
- JNI 日期值转换问题,在C++中获取不同的长整型值
- JNI,使用两个 .so 文件时出错,其中一个文件需要另一个文件
- Winapi - SetWindowLongPtr in ShutdownBlockReason创建/销毁JNI本机代码
- 将预编译的 C 共享库与 JNI/NDK 结合使用
- JNI 在应用程序中检测到错误:在为 innerclass 调用 NewObject 时使用了无效的 jobject
- 使用 jni 将返回带有模板的对象的 Java 代码转换为 c++
- 无法将DefineClass(JNI)与Qt资源一起使用
- 使用本机 JNI 静态方法实现C++ Java 运行时错误
- 从C++调用dll实现的JNI
- 如何在JNI中从线程内部调用JAVA方法
- 如何从 C/C++ 在 JNI for Java 中创建 UTF16 字符串?