2012-03-09 2 views
12

를 부착 내가 JNI 콜백이 :이 (빈 유용한 코드)처럼 실행하면JNI가/분리 스레드 메모리 관리

void callback(Data *data, char *callbackName){ 
    JNIEnv *env; 
    jvm->AttachCurrentThread((void **)&env, NULL); 
    /* start useful code*/ 

    /* end useful code */ 
    jvm->DetachCurrentThread(); 
} 

, 나는 메모리 누수를 얻을. 전체 방법을 주석 처리하면 누수가 없습니다. 스레드를 연결/분리하는 올바른 방법은 무엇입니까?

내 응용 프로그램은 실시간 사운드 데이터를 처리하므로 다른 배치를 준비하려면 데이터 처리를 담당하는 스레드를 가능한 한 빨리 완료해야합니다. 따라서 이러한 콜백을 위해 새 스레드를 만듭니다. 매 초마다 수십 또는 수백 개의 JVM이 있고 그래프를 다시 그린 콜백 함수를 호출하고 분리하고 죽습니다. 이게이 일을하는 올바른 방법일까요? 누출 된 메모리를 처리하는 방법?

편집 : 오타

내가 필요한 mimimal 코드를 만든 OK :

package test; 

public class Start 
{ 
    public static void main(String[] args) throws InterruptedException{ 
     System.loadLibrary("Debug/JNITest"); 
     start(); 
    } 

    public static native void start(); 
} 

#include <jni.h> 
#include <Windows.h> 
#include "test_Start.h" 

JavaVM *jvm; 
DWORD WINAPI attach(__in LPVOID lpParameter); 

JNIEXPORT void JNICALL Java_test_Start_start(JNIEnv *env, jclass){ 
    env->GetJavaVM(&jvm); 
    while(true){ 
     CreateThread(NULL, 0, &(attach), NULL, 0, NULL); 
     Sleep(10); 
    } 
} 


DWORD WINAPI attach(__in LPVOID lpParameter){ 
    JNIEnv *env; 
    jvm->AttachCurrentThread((void **)&env, NULL); 
    jvm->DetachCurrentThread(); 
    return 0; 
} 

와 나는 VisualJM 프로파일을 실행할 때, 나는 보통 톱니 패턴을 얻을 수를, 거기에 누출이 없습니다. 힙 사용량은 약 5MB에서 최고를 기록했습니다. 그러나 프로세스 탐색기를 실제로 관찰하는 것은 이상한 행동을 보여줍니다. 메모리가 천천히 상승하고 상승하며, 1 분 동안 4K를 1 초마다 실행 한 다음 갑자기이 할당 된 메모리를 모두 삭제합니다. 이러한 드랍스는 가비지 콜렉션과 일치하지 않습니다 (프로파일 링의 톱니보다 메모리가 덜 자주 할당되고 할당량이 줄어 듭니다).

내 최선의 방법은 수만 밀리 세컨드 스레드를 처리하는 일부 OS 동작입니다. 어떤 전문가는 이에 대한 설명이 있습니까? 네이티브 코드에서 다시 자바로 호출에 대한

답변

7

문제가 발생했습니다. 내가 파괴하지 않은 JNI 코드에서 로컬 참조가 매달려있었습니다. 모든 콜백은 새로운 로컬 참조를 만들므로 메모리 누수가 발생합니다. 로컬 참조를 전역으로 변환 할 때 재사용 할 수 있었지만 문제는 사라졌습니다.

14

몇 가지 포인트 : jvm- 경우에만

  • AttachCurrentThread와를 호출해야>의 GetEnv()는 0 값을 반환합니다. 스레드가 이미 연결되어 있으면 일반적으로 아무 작업도 수행하지 않지만 일부 오버 헤드는 줄일 수 있습니다.
  • AttachCurrentThread를 호출 한 경우에만 DetachCurrentThread를 호출해야합니다.
  • 향후 동일한 스레드에서 호출 될 것으로 예상되는 경우 분리를 피하십시오.

네이티브 코드의 스레딩 동작에 따라 분리를 피하고 대신 종료시 처리 할 수 ​​있도록 모든 원시 스레드에 대한 참조를 저장해야 할 수 있습니다 (그렇게해야하는 경우에도 응용 프로그램에 의존 할 수 있습니다 청소를 위해 종료).

네이티브 스레드를 계속 연결하고 분리하는 경우 VM은 (종종 동일한) 스레드를 Java 객체와 계속 연관시켜야합니다. 일부 VM은 성능을 향상시키기 위해 스레드를 다시 사용하거나 매핑을 일시적으로 캐시 할 수 있지만, VM을 사용하여 성능을 향상시키지 않으면 더 정확하게 예측할 수 있습니다.

+0

나는 귀하의 요지를 볼 수 있으며, 나는 보통 동의합니다. 내가 만들고있는 스레드는 실제로 수명이 짧습니다. 나는 (WinApi CreateThread를 사용하여) 그것들을 만들고, 즉시 그들을 JVM에 붙인다.Java에서는 Swing 그래프를 새 값으로 다시 그립니다. 작업이 완료되면 분리되어 실행을 중지합니다 (0을 반환).이 시점에서 OS에 의해 파기되어야합니다. 그것들은 Java에 새로운 가치를 전달하는 데 사용됩니다. 각 사운드 채널에 대해 약 초당 약 40 개가 있습니다 (최대 32 개 채널로 작업합니다). –

+0

스레드 풀링을 고려할 수 있습니다. 새 스레드를 지속적으로 생성하는 대신 스레드를 오래 머무르게하고 큐에서 입력을받습니다. 이렇게하면 OS와 Java에서 스레드 관리 오버 헤드가 줄어 듭니다. – technomage

+0

JNI에서 메소드를 호출하는 것 외에 다른 Java 작업을 수행하는 경우 해당 작업을 중심으로 로컬 프레임을 푸시/팝 할 수도 있습니다. – technomage