nav*_*ave 3 c c++ java java-native-interface memory-leaks
所以我在Java中有以下JNIManager类.在这个类中,正如您所看到的,我定义了一个名为setUpBackGround()的本机方法;
public class JNIManager{
public native void setUpBackground();
public void messageMe(byte[] byteArray);
}
Run Code Online (Sandbox Code Playgroud)
然后我有另一个用本机(C)代码实现的类.我们称这个类为Background Class.这个类做了一些后台工作,并调用JNIManager类的messageMe()方法传递一个byte [].
class Background{
JNIEnv* mJNIEnv;
jbyteArray mArray;
jobject mJObject;
Background(JNIEnv * env, jobject jObject){
mArray = env->NewByteArray(1040);
mJNIEnv = env;
mJObject = jObject;
}
virtual ~Background(){
mJNIEnv->DeleteLocalRef(mArray); //is this necessary?
}
void someMethod(){
jclass manager = mJNIEnv->GetObjectClass(mJObject);
jmethodID method = mJNIEnv->GetMethodID(manager, "messageMe", "([B)V");
mJNIEnv->CallVoidMethod(mJObject, method, mArray);
mJNIEnv->DeleteLocalRef(manager); // is this necessary?
}
}
Run Code Online (Sandbox Code Playgroud)
现在,在本机方法setUpBackground中,我执行以下操作,
JNIEXPORT jlong JNICALL Java_com_example_test_JNIManager_setUpBackground
(JNIEnv * env, jobject jo){
Background* back = new Background(env,jo);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
最后,在另一个类的方法中,我创建了一个JNIManager实例并调用本机方法setUpBackground().
otherMethod(){
JNIManager jniManager = new JNIManager();
jniManager.setUpBackground();
}
Run Code Online (Sandbox Code Playgroud)
关于这整个设置,我有2个问题.
1)当jniManager在上述方法结束时超出范围时,我使用"new"关键字动态创建的Background类是否会自动被垃圾收集?我认为它不会,并将导致内存泄漏.它是否正确?如果是这样,我该怎么做才能纠正?
2)是否需要DeleteLocalRef()调用以避免内存泄漏,或者JVM是否会在不再使用它们时处理删除它们的任务?
更新 - 遵循nneonneo的回答
public class JNIManager{
private long nativeHandle;
public JNIManager(){
nativeHandle = setUpBackground();
}
public native long setUpBackground();
public native void releaseBackground(long handle);
public void messageMe(byte[] byteArray) {//do some stuff};
}
Run Code Online (Sandbox Code Playgroud)
更新了背景课程
class Background{
public:
JavaVM* mJvm;
JNIEnv* mJNIEnv;
jobject mJObject;
jbyteArray mArray;
int file;
Background(JNIEnv * env, jobject jObject){
env->GetJavaVM(&mJvm);
attachToThread();
mJObject = env->NewGlobalRef(jObject);
mArray = env->NewByteArray(1040);
file = 1; //Does this need to be a globalRef ?
}
void destroy(){
mJNIEnv->DeleteGlobalRef(mArray);
mJNIEnv->DeleteGlobalRef(mJObject);
mJvm = NULL;
mJNIEnv = NULL;
file = 0;
}
void someMethod(){
attachToThread();
jclass manager = mJNIEnv->GetObjectClass(mJObject);
jmethodID method = mJNIEnv->GetMethodID(manager, "messageMe", "([B)V");
mJNIEnv->CallVoidMethod(mJObject, method, mArray);
mJNIEnv->DeleteLocalRef(manager);
detachFromThread();
}
void attachToThread(){
mJvm->AttachCurrentThread(&mJNIEnv, NULL);
}
void detachFromThread(){
mJvm->DetachCurrentThread();
}
}
Run Code Online (Sandbox Code Playgroud)
更新了原生方法
JNIEXPORT jlong JNICALL Java_com_example_test_JNIManager_setUpBackground
(JNIEnv * env, jobject jo){
Background* back = new Background(env,jo);
return reinterpret_cast<jlong>(back);
}
JNIEXPORT jlong JNICALL Java_com_example_test_JNIManager_releaseBackground
(JNIEnv * env, jobject jo, jlong handle){
Background* back = reinterpret_cast<Background* back>(handle);
back.destroy();
delete back;
}
Run Code Online (Sandbox Code Playgroud)
更新了otherMethod
otherMethod(){
JNIManager jniManager = new JNIManager();
//Do some stuff...
jniManager.releaseBackground();
}
Run Code Online (Sandbox Code Playgroud)
我不确定第一点.
"JNInvs在JNI调用之间可能不会保持相同(特别是,两个不同的线程将具有不同的JNIEnv)".
这是否意味着一旦setupBackground()JNI调用返回,当前线程被删除?由于在这个线程中创建了Background类,这个类的方法(例如someMethod())不会在同一个线程上运行吗?如果没有,attachToThread()方法是否定义了获取当前线程并使用其JNIEnv*的正确方法?
我基本上需要在JNIManager的整个生命周期中创建的Background对象.然后偶尔调用Background对象的someMethod()(由一些外部类),然后这将调用JNIManager类中的messageMe()方法(如代码中所示).
你做错了几件事.
JNIEnv在JNI方法返回后,您无法存储引用.JNIEnv在JNI调用之间可能不会保持相同(特别是,两个不同的线程将具有不同的JNIEnvs,并且Java类终结器可以在单独的线程上运行).
在JNI方法返回后,您无法存储LocalRefs.从JNI函数返回时,将删除所有本地引用.如果需要保留对对象的引用,请使用全局引用(然后由您负责删除).双方mArray并mJObject必须是全球性的引用.
是的,你有泄漏.你没有delete back任何地方,实际上你甚至没有把它的地址存储在任何地方,所以它会泄漏.如果你打算Background成为一个单例类,那么实际上使用一个合适的单例模式来实现它.如果您打算将生命周期与生命周期Background联系起来JNIManager,那么您必须添加适当的终结代码JNIManager来销毁Background实例(并将Background实例存储在某处,例如在JNIManager类实例上).
| 归档时间: |
|
| 查看次数: |
885 次 |
| 最近记录: |