SORU
2 Aralık 2013, PAZARTESİ


Yerli iplik geri çağırırken Java iş parçacığı sızıntıları ile JNI

Özet: özgün olarak oluşturulan iş parçacığı. bir yerel kod Java içine geri çağırma zaman, Java iplik kaçakları görüyorum

(Güncelleme 11 Şubat 2014: Oracle ile bir destek talebi olarak yetiştirdik. Şimdi confirmed Java 7 update 45 Oracle ile olmuştur. Sadece 64-bit (ve muhtemelen Mac Linux platformlar etkiler: etkilenmez Linux 32-bit).

(29 Nisan 2014 güncelleme: Oracle bu sorun için bir düzeltme var, ve Java 7 update 80) çıkacak.

Bir uygulama bir Java katmanı ve yerel bir kütüphaneden ibaret. JNI aracılığıyla yerel kütüphaneye Java katman aramalar: bu daha sonra geri Java içine çağıran çalışmaya başlayacağı yerel bir iş parçacığı neden olur. Yeni yerli iplik JVM bağlı olduğundan, geri arama yapmadan önce eklenecek, daha sonra müstakil ihtiyacı var. Bunu yapmak için her zamanki gibi AttachCurrentThread / DetachCurrentThread çağrıları ile geri Java içine çağıran kod dirsek gibi görünüyor. Bu gayet iyi çalışıyor, ama bizim uygulama geri Java çok sık çağırır) ve her zaman ekleme ayırma yükü önemli.

Orada bir iyileştirme açıklanan birkaç yerde (gibi here here) önerir kullanarak mekanizmaları temel parçacığı yerel depolama ortadan kaldırmak için bu sorun: aslında her zaman yerel geri arama tetiklenir, iplik test, eğer zaten takılı olan JVM: değilse, bağlı JVM ve iş parçacığı yerel depolama mekanizması için kullanılır otomatik olarak ayır konu ne zaman çıkar. Bu hayata, ama takmak ve bağlantısını kesin doğru gerçekleşen görünüyor olsa da, bu Java tarafında konuları bir sızıntısına neden olur. Her şeyi doğru yaptığımı düşünüyorum ve yanlış ne olabilir görmek için mücadele ediyorum. Bir süredir bu konuda kafamda sopa ve herhangi bir anlayış için çok minnettar olacaktır.

-Kapa şeklinde sorunu yeniden var. Aşağıda yerli katman kodunu. Biz burada bir anlamda bu kapsüller sürecinin dönen bir JNİEnv işaretçi için geçerli iş parçacığı kullanarak POSIX iş parçacığı yerel depolama mekanizması otomatik olarak ayır parçacığı olmasaydı zaten bağlı. Java geri arama yöntemi için bir proxy gibi davranan geri bir sınıf yoktur. (Ve bu soruna ilgisiz olan Java nesne), genel nesne başvurularını oluşturma ve silme ekstra komplikasyon ortadan kaldırmak için statik bir Java yöntemine geri kullandım. Nihayet aradığında, bir geri arama yapar, ve yeni bir yerel iş parçacığı oluşturur ve tamamlamasını bekler JNI bir yöntem yoktur. Yeni oluşturulan bu konuyu sonra geri çıkar diyor.

#include <jni.h>
#include <iostream>
#include <pthread.h>


using namespace std;


/// Class to automatically handle getting thread-specific JNIEnv instance,
/// and detaching it when no longer required
class JEnvWrapper
{

public:

    static JEnvWrapper &getInstance()
    {
        static JEnvWrapper wrapper;
        return wrapper;
    }

    JNIEnv* getEnv(JavaVM *jvm)
    {
        JNIEnv *env = 0;
        jint result = jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
        if (result != JNI_OK)
        {
            result = jvm->AttachCurrentThread((void **) &env, NULL);
            if (result != JNI_OK)
            {
                cout << "Failed to attach current thread " << pthread_self() << endl;
            }
            else
            {
                cout << "Successfully attached native thread " << pthread_self() << endl;
            }

            // ...and register for detach when thread exits
            int result = pthread_setspecific(key, (void *) env);
            if (result != 0)
            {
                cout << "Problem registering for detach" << endl;
            }
            else
            {
                cout << "Successfully registered for detach" << endl;
            }
        }

        return env;
    }

private:

    JEnvWrapper()
    {
        // Initialize the key
        pthread_once(&key_once, make_key);
    }

    static void make_key()
    {
        pthread_key_create(&key, detachThread);
    }


    static void detachThread(void *p)
    {
        if (p != 0)
        {
            JavaVM *jvm = 0;
            JNIEnv *env = (JNIEnv *) p;
            env->GetJavaVM(&jvm);
            jint result = jvm->DetachCurrentThread();
            if (result != JNI_OK)
            {
                cout << "Failed to detach current thread " << pthread_self() << endl;
            }
            else
            {
                cout << "Successfully detached native thread " << pthread_self() << endl;
            }

        }
    }


    static pthread_key_t key;
    static pthread_once_t key_once;
};

pthread_key_t JEnvWrapper::key;
pthread_once_t JEnvWrapper::key_once = PTHREAD_ONCE_INIT;



class Callback
{

public:

    Callback(JNIEnv *env, jobject callback_object)
    {
        cout << "Constructing callback" << endl;
        const char *method_name = "javaCallback";
        const char *method_sig = "(J)V";

        env->GetJavaVM(&m_jvm);

        m_callback_class = env->GetObjectClass(callback_object);
        m_methodID = env->GetStaticMethodID(m_callback_class, method_name, method_sig);
        if (m_methodID == 0)
        {
            cout << "Couldn't get method id" << endl;
        }
    }

    ~Callback()
    {
        cout << "Deleting callback" << endl;
    }

    void callback()
    {
        JNIEnv *env = JEnvWrapper::getInstance().getEnv(m_jvm);
        env->CallStaticVoidMethod(m_callback_class, m_methodID, (jlong) pthread_self());
    }

private:

    jclass m_callback_class;
    jmethodID m_methodID;
    JavaVM *m_jvm;
};



void *do_callback(void *p)
{
    Callback *callback = (Callback *) p;
    callback->callback();
    pthread_exit(NULL);
}




extern "C"
{

JNIEXPORT void JNICALL Java_com_test_callback_CallbackTest_CallbackMultiThread(JNIEnv *env, jobject obj)
{
    Callback callback(env, obj);
    pthread_t thread;
    pthread_attr_t attr;
    void *status;
    int rc;

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    rc = pthread_create(&thread, &attr, do_callback, (void *) &callback);
    pthread_attr_destroy(&attr);
    if (rc)
    {
        cout << "Error creating thread: " << rc << endl;
    }
    else
    {
        rc = pthread_join(thread, &status);
        if (rc)
        {
            cout << "Error returning from join " << rc << endl;
        }
    }
}

Java kod çok basit: sadece sürekli bir döngü içinde: yerel yöntemini çağırır

package com.test.callback;

public class CallbackTest
{

    static
    {
        System.loadLibrary("Native");
    }

    public void runTest_MultiThreaded(int trials)
    {
        for (int trial = 0; trial < trials; trial  )
        {
            // Call back from this thread
            CallbackMultiThread();

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    static void javaCallback(long nativeThread)
    {
        System.out.println("Java callback: native thread: "   nativeThread   ", java thread: "   Thread.currentThread().getName()   ", "   Thread.activeCount()   " active threads");
    }

    native void CallbackMultiThread();  
}

Aşağıda bazı örnek çıktı bu test: gördüğünüz gibi bu, ancak yerli katmanı olduğunu bildiriyor yerli iplik başarılı olmak bağlı ve müstakil, her zaman geri tetiklenir yeni bir Java iş parçacığı oluşturulur:

Constructing callback
Successfully attached native thread 140503373506304
Successfully registered for detach
Java callback: native thread: 140503373506304, java thread: Thread-67, 69 active threads
Successfully detached native thread 140503373506304
Deleting callback
Constructing callback
Successfully attached native thread 140503373506304
Successfully registered for detach
Java callback: native thread: 140503373506304, java thread: Thread-68, 70 active threads
Successfully detached native thread 140503373506304
Deleting callback
Constructing callback
Successfully attached native thread 140503373506304
Successfully registered for detach
Java callback: native thread: 140503373506304, java thread: Thread-69, 71 active threads
Successfully detached native thread 140503373506304
Deleting callback
Constructing callback
Successfully attached native thread 140503373506304
Successfully registered for detach
Java callback: native thread: 140503373506304, java thread: Thread-70, 72 active threads
Successfully detached native thread 140503373506304
Deleting callback
Constructing callback
Successfully attached native thread 140503373506304
Successfully registered for detach
Java callback: native thread: 140503373506304, java thread: Thread-71, 73 active threads
Successfully detached native thread 140503373506304
Deleting callback

Sadece eklemek için: 6.3 (64-bit) Otomotiv kullanıyorum platform. Java sürümü Oracle dağıtım sürümü sorun da OpenJDK dağıtım sürümleri ile gösterse 1.7.0_45, 1.7 ve 1.6.

CEVAP
22 NİSAN 2012, Pazar


Eclipse.org bu makale başlamak için en yararlı buldum.

Kod hata ayıklama başlamak için iyi bir yer org üzerinde kesme noktası ayarlamak için.eclipse.jdt.çekirdek.dom.yeniden yazmak.ASTRewrite, özellikle rewriteAST (), sonra da bazı refactorings tetik yöntemi.

Burada işinize yarayabilecek bir kaç. Özellikle aradığınız bir şey var mı veya AST süreç nasıl genel anlamda?

http://www.ibm.com/developerworks/opensource/library/os-ast/  
http://blog.sahits.ch/?p=228
http://www.vogella.com/articles/EclipseJDT/article.html

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Darren Kitchen

    Darren Kitch

    3 EKİM 2011
  • FUzzyBUnnyBOoties

    FUzzyBUnnyBO

    3 EKİM 2007
  • Metheud

    Metheud

    9 EYLÜL 2006