我正在将橡皮擦数据竞争检测算法的实现作为JVMTI代理。 当我尝试运行一些示例输入来测试我的代码时,JVM崩溃,转储如下所示(也可能显示同一错误的其他堆栈跟踪):
FATAL ERROR in native method: Using JNIEnv in the wrong thread
at Proxy.monitor_enter_(Native Method)
at Proxy.monitor_enter(Proxy.java:30)
at ex1.LifeThreads.setNeighborThreadChange(LifeThreads.java:36)
at ex1.LifeThreads.neighbor(LifeThreads.java:425)
at ex1.LifeThreads.standardItr(LifeThreads.java:321)
at ex1.LifeThreads.run(LifeThreads.java:462)
(这种事后跟踪可以使用-Xcheck:jni选项获取Sun JVM)
在代码中,我执行与各种JDK示例(heapViewer,heapTracker等等)中显示的相同类型的检测,通过一些使用本机方法的代理java类。在每个Proxy.monitor_enter_
指令后调用monitorenter
本机方法。
这是monitor_enter _:
的代码void native_monitor_exit(JNIEnv *jni, jclass klass, jthread thread_id, jobject obj)
{
scoped_lock( agent::instance()->jvmti(), agent::instance()->monitor_ );
if( agent::instance()->death_active_)
return;
std::string name = agent::instance()->thread_name( thread_id );
thread_t* thread = get_thread( thread_id );
if( thread == 0 )
return;
jobject global_ref = agent::instance()->jni()->NewGlobalRef( obj );
if( global_ref == 0 )
fatal_error("Out of memory while trying to create new global ref.");
logger::instance()->level(1) << "MONITOR ENTER"
<< "\n\t" << "jthread name= " << name
<< "\n\t" << "thread_t= " << thread << " " << *thread
<< "\n\t" << "monitor gl= " << global_ref
<< std::endl;
thread->lock( lock(global_ref) );
}
,其中scoped_lock
基本上是JVMTI Raw Monitor进入/退出的作用域锁,
thread_t
只是一个包含一些std::vector
的结构,其中存储了类lock
的实例(它本身只包含jobject
全局引用global_ref
),thread->lock( lock(global_ref))
1}}被调用。
JVMTI env。在代理单例中全局缓存,而线程局部的JNI env每次使用前都会重新加载(效率不高,但现在我不在乎),如下所示:
JNIEnv* jni()
{
jint res;
JNIEnv* env = 0;
res = jvm()->GetEnv( (void**)&env, JNI_VERSION_1_2 );
if( res == JNI_EDETACHED )
{
res = jvm()->AttachCurrentThread( (void **)&env, 0 );
if( res != JNI_OK || env == 0 )
fatal_error( "ERROR: Unable to create JNIEnv by attach, error=%d\n", res );
}
else if( res != JNI_OK || env == 0 )
fatal_error( "ERROR: Unable to create JNIEnv, error=%d\n", res );
}
return env;
}
答案 0 :(得分:0)
您应该使用传递给jni
方法的native_monitor_exit
参数,而不是在jni()
方法中查找它,这是您在方法时应该使用的jni环境从Java调用。