2012-08-23 2 views
5

후, 나는 오류가 얻을 "JNI 로컬 심판 테이블에 추가에 실패했습니다 512 개 항목"이것은 내 코드JNI 테이블 오버 플로우도 deleteLocalRef

입니다 몇 가지 제안,하지만 그들 중 누구도 작동합니다! DeleteLocalRef에도 불구하고 작동하지 않습니다. 이 함수는 말 그대로 모든 함수를 호출하는 프로파일 러에 사용됩니다 ...

+0

이것이 ref 테이블을 채우는 코드입니까? 하드 코딩 된 하나의 상수 pJNIData를 사용할 때 문제가 사라지나요? –

+0

@vtmarvin 확실하지 않습니다. 이것은 참조 테이블과 차이가 있습니까? -> JNIEnv * pJNIEnv = profilerGetJNIEnv(); 경우 (pJNIEnv!) \t \t { \t \t \t LOGE ("프로파일 ERROR :! 자바 환경 (널)에없는"); \t \t \t return; \t \t} –

답변

2

Java 코드라는 JNI 방법 (이 경우 메서드는 정적이 아님)을 보았을 때 이것을 보았습니다. 알다시피, 사용되지 않는 로컬 참조는 Java 메서드가 JNI에서 호출 될 때 (즉, 최상위 JNI 함수가 반환 될 때까지) 자동으로 삭제 된 이 아니며이 자동으로 삭제됩니다.

IIRC 이미 로그의 메모리 개체에 대한 정보가 있거나 일부 로깅을 추가 할 수 있습니다. 그 정보로부터 나는 내가 언급하지 않은 쓰레기 항목을 확인했다. 그것들은 두 개의 배열과 클래스 였지만 이후 호출에서는 생성되었지만 가비지 수집되지는 않았습니다.

// in a function that calls a Java method from JNI 
jbyteArray srcArray = env->NewByteArray(len); 
jclass cls = env->FindClass("com/something/MyClass"); 
jmethodID mid = env->GetMethodID(cls, "mymethod", "([BI)[B"); 
jbyteArray resArray = (jbyteArray)env->CallObjectMethod(obj, mid, srcArray, XXXX); 

... 
env->DeleteLocalRef(cls); 
env->DeleteLocalRef(resArray); 
env->DeleteLocalRef(srcArray); 
// no need to do anything with mid 

이러한 세 가지 로컬 참조가 다르게 얻어졌지만, 모두가 어슬렁 거리고있었습니다.

유용한 링크 : 이 http://www.netmite.com/android/mydroid/dalvik/docs/jni-tips.html#local_vs_global_references (또는 달빅 VM 워드 프로세서의 달빅/문서/JNI-tips.html을 찾아 "대 글로벌 참조를 지역"섹션을 찾습니다) 모든는 JNI에서 반환하는 객체

것은입니다 "지역 참조". 이것은 현재 스레드에서 현재 네이티브 메소드의 지속 기간 동안 유효 함을 의미합니다. 원시 메소드가 리턴 된 후에도 오브젝트 자체가 계속 실행 되더라도 참조는 유효하지 않습니다. 이것은 jclass 및 jarray를 포함하여 jobject의 모든 하위 클래스에 적용됩니다. [...] 참고 : 메서드 및 필드 ID는 객체 참조가 아닌 32 비트 식별자이며 NewGlobalRef에 전달하면 안됩니다. GetStringUTFChars 및 GetByteArrayElements와 같은 함수에서 반환 된 원시 데이터 포인터도 객체가 아닙니다.

0

다른 사람이이 문제에 부딪 힐 경우에 대비해 생각했습니다. 이것은 몇 시간 동안 혼란 스러웠던 이상한 경우입니다!

좋아, 그럼 NDK를 애플 리케이션과 호출되는 자바 코드는 런타임에로드되는 apk 내부입니다. 런타임 로딩이 어떤 식 으로든 영향을 미치는지는 모르겠지만 언급해야한다고 생각했습니다.

이제 C++ 메소드에서 find 클래스와 getmethodid를 사용하여 생성자를 HashMap에 가져 와서 새 HashMap 인스턴스를 가져 오기 위해 호출합니다. 그런 다음 jni 호출을 사용하여 C++ 측에서 HashMap을 채 웁니다. 여태까지는 그런대로 잘됐다. 그런 다음 HashMap을 Java 코드로 전달하고, 다시 모든 것이 예상대로 작동합니다. 자바 코드가 반환되면 HashMap에서 DeleteLocalRef를 호출합니다. 오류는 발생하지 않지만 참조 은 삭제되지 않습니다.

이것은 512 개의 로컬 참조를 (이 함수를 여러 번 호출하여) 마지막으로 실행했을 때만 나타 났으며 오류 덤프는 localref 저장소의 마지막 10 개 항목이 거의 모든 HashMaps임을 보여줍니다. 나는 GC가 멀티 쓰레드 (multithreaded) ndk 앱을 만들 때 메서드의 끝에서이 참조를 수집하지 않는다는 것을 이해할 것이다. 그러나 DeleteLocalRef가 작동 했어야합니다.

수정 : I는 I 쓴 자바 메소드에 JNI 호출의 해시 MAP 만들면 괜찮이고, 상기 기준은 다음 free'able 것을 발견 결국 . 말 그대로 문자 그대로 새로운 HashMap을 반환하는 자바 함수를 가지고있는 것이 당연한 것 같습니다. 그러나 지금까지는 그것과 함께 살았습니다 :)

관련 문제