例如:做@H_404_3@
Log.v("?",Long.toString(Debug.getNativeHeapAllocatedSize())); ByteBuffer buffer = allocateDirect(LARGE_NUMBER); buffer=null; System.gc(); Log.v("?",Long.toString(Debug.getNativeHeapAllocatedSize()));
在日志中给出两个数字,第二个数字比第一个数字大至少LARGE_NUMBER.@H_404_3@
如何摆脱这种泄漏?@H_404_3@
按照Gregory在C方面处理alloc / free的建议,然后定义@H_404_3@
JNIEXPORT jobject JNICALL Java_com_foo_bar_allocNative(JNIEnv* env,jlong size) { void* buffer = malloc(size); jobject directBuffer = env->NewDirectByteBuffer(buffer,size); jobject globalRef = env->NewGlobalRef(directBuffer); return globalRef; } JNIEXPORT void JNICALL Java_com_foo_bar_freeNative(JNIEnv* env,jobject globalRef) { void *buffer = env->GetDirectBufferAddress(globalRef); free(buffer); env->DeleteGlobalRef(globalRef); }
然后在JAVA一边得到我的ByteBuffer@H_404_3@
ByteBuffer myBuf = allocNative(LARGE_NUMBER);
并释放它@H_404_3@
freeNative(myBuf);
不幸的是,虽然它分配的很好,它a)仍然保留根据Debug.getNativeHeapAllocatedSize()分配的内存和b)导致错误@H_404_3@
W/dalvikvm(26733): JNI: DeleteGlobalRef(0x462b05a0) Failed to find entry (valid=1)
我现在彻底迷惑了,我以为我至少明白了C方面的事情…为什么是free()没有返回内存?我在DeleteGlobalRef()中做错了什么?@H_404_3@
解决方法
ByteBuffer.allocateDirect()从本机堆/免费存储(认为malloc())分配内存,然后将其包装到ByteBuffer实例中.@H_404_3@
当ByteBuffer实例收集垃圾内容时,回收本机内存(否则将泄漏本机内存).@H_404_3@
您正在调用System.gc(),希望立即回收原生内存.但是,调用System.gc()只是一个请求,它解释了为什么你的第二个日志语句不会告诉你内存已经被释放:这是因为还没有!@H_404_3@
在您的情况下,Java堆中的空闲内存显然足够,垃圾收集器决定不执行任何操作:因此,不可访问的ByteBuffer实例尚未收集,其终结器不会运行,并且本机内存不会被释放.@H_404_3@
此外,请注意JVM中的这个bug(不知道它如何适用于Dalvik),其中大量分配的直接缓冲区导致不可恢复的OutOfMemoryError.@H_404_3@
你对JNI做的事情做了评论.这实际上是可能的,你可以实现以下几点:@H_404_3@
>发布本机ByteBuffer allocateNative(long size)入口点:@H_404_3@
调用void * buffer = malloc(size)来分配本地内存
>将新分配的数组转换为ByteBuffer实例,并调用(* env) – > NewDirectByteBuffer(env,buffer,size);
>使用(* env) – > NewGlobalRef(env,directBuffer)将ByteBuffer本地引用转换为全局引用.@H_404_3@
>发布一个native void disposeNative(ByteBuffer buffer)入口点:@H_404_3@
在*(env) – > GetDirectBufferAddress(env,directBuffer)返回的直接缓冲区地址上调用free();
>使用(* env) – > DeleteGlobalRef(env,directBuffer)删除全局参考;@H_404_3@
一旦你在缓冲区上调用了disposeNative,那么你不应该使用引用,所以它可能非常容易出错.重新考虑您是否真的需要对分配模式进行明确的控制.@H_404_3@
忘记我关于全局参考的内容.实际上,全局引用是一种在本机代码中存储引用的方法(如全局变量),以便进一步调用JNI方法可以使用该引用.所以你会有:@H_404_3@
>从Java中调用本地方法foo(),该方法从本地引用(通过从本机创建对象获取)创建全局引用,并将其存储在本机全局变量(作为作业)中)
再次从Java中调用本地方法bar(),它获取foo()存储的jobject并进一步处理它
>最后,仍然从Java,最后一次调用native baz()会删除全局引用@H_404_3@
对困惑感到抱歉.@H_404_3@