Сбой агента JVMTI - PullRequest
       22

Сбой агента JVMTI

2 голосов
/ 14 сентября 2011

Я работаю над реализацией алгоритма обнаружения гонки данных ластика в качестве агента 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 Monitorenter / exit, thread_t - это просто структура, заключающая в себе некоторую std::vector, где хранится экземпляр класса lock (который сам по себе просто содержит jobject глобальную ссылку global_ref), когда вызывается thread->lock( lock(global_ref)).

JVMTI env.глобально кэшируется в агенте singleton, тогда как 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;
}

1 Ответ

0 голосов
/ 10 апреля 2012

Вы должны использовать параметр jni, который передан вашему методу native_monitor_exit, вместо того, чтобы искать его в вашем методе jni(), это среда jni, которую вы должны использовать при вызове метода из Java.

...