jna ByteBuffer的没有得到释放,导致C堆中耗尽内存

[url]http://codego.net/99906/[/url]


说,我怎么JNA和Java直接拨款的理解充其量是内脏,所以我试图描述我对什么事情的理解开始。任何更正,除了反应将是巨大的... 我跑了混合了Java和C JNA本地应用程序和正在运行进行的跨与Java垃圾收集器不能自由引用的直接分配一个可重复的问题,导致了C堆耗尽 我敢肯定,我的C应用程序是不是配置问题的来源,因为我传递一个java.nio.ByteBuffer进入我的C代码 CodeGo.net,修改缓冲区中,然后在访问我的Java函数的结果。我有一个单一的malloc和一个单一的对应free每个函数调用过程中,但经过反复运行代码Java中的malloc最终将失败。 下面是一个代码轻视集,展示的问题-现实我试图拨出约在C堆函数调用时16至32MB。 我的Java代码的作用,如:
public class MyClass{
public void myfunction(){
ByteBuffer foo = ByteBuffer.allocateDirect(1000000);
MyDirectAccessLib.someOp(foo, 1000000);
System.out.println(foo.get(0));
}
}
public MyDirectAccessLib{
static {
Native.register("libsomelibrary");
}
public static native void someOp(ByteBuffer buf, int size);
}
然后,我的C代码可能是这样:
#include <stdio.h>
#include <stdlib.h>
void someOp(unsigned char* buf, int size){
unsigned char *foo;
foo = malloc(1000000);
if(!foo){
fprintf(stderr, "Failed to malloc 1000000 bytes of memory\n");
return;
}
free(foo);
buf[0] = 100;
}
trouble的是调用这个函数反复Java堆是稳定的(它生长缓慢),但C函数最终不能分配任何在较高的水平,我相信这就是Java是C堆中,但不清理的ByteBuffer指向在后在Java ByteBuffer的目的是比较小的。 据我发现在我的函数手动运行GC将提供所需的清理工作,但是这似乎是一个既可怜的想法,一个贫穷的解决方案。 我该如何处理这个问题更好,这样的ByteBuffer的空间被适当地释放,我的C堆空间被控制? 是我对问题的理解不正确(在那里,我跑不正确)? 编辑:缓冲区大小,以更好地反映我的实际应用,我在分配给图像约3000X2000 ...
本文地址 :CodeGo.net/99906/

-------------------------------------------------------------------------------------------------------------------------
1. 我认为你已经正确的诊断:你永远不会耗尽Java堆的,因此JVM没有垃圾收集,并且映射缓冲区不会被释放。您手动运行GC的时候没有问题,这似乎证实了这一点。你也可以打开详细日志记录集合作为一个二次确认。 所以,你可以做什么?嗯,我想尝试的优先件事是要保持初始JVM堆大小小,使用-这可能的问题 CodeGo.net,如果你的程序是不断的小分配上的Java堆,因为它会更频繁地运行GC。 我最好的PMAP工具(或任何等值是在Windows上),研究地图。这有可能是你的C堆中,通过分配可变大小的缓冲区。如果是这样的话,那么你会看到每一个大的虚拟地图,用“匿名”块之间的差距。而解决办法是分配常数大小的块是大于你所需要的。
2. 你实际上是在面临Java VM的一个已知的bug。在bug报告中列出的最佳解决方法是: “该-XX:。MaxDirectMemorySize=选项可以限制使用量来分配,将这个限制被超过一个完整的GC,从而挑起参考处理和未引用的缓冲区释放的尝试” 其他可能的解决方法包括: 偶尔插入显式System.gc()的调用,以确保直接缓冲区 减轻年轻一代的尺寸给力更频繁的GC。 明确集中直接缓冲区在应用程序级别。 如果你真的想依靠直接字节缓冲区,那么我会建议汇集在应用程序级别。根据您的应用程序,你甚至可能只是高速缓存和缓冲区(小心多线程)。
3. 我怀疑你的问题是由于直接字节缓冲区。他们可以在Java堆之外分配。 如果你频繁调用,以及分配小的缓冲区每个模式可能不是一个很好的适合直接缓冲区。 为了找出问题所在,我会切换到(Java)的堆中分配的缓冲区(该allocate替代方法allocateDirect。如果让问题消失,你已经找到了罪魁祸首。接下来的问题将是一个直接字节缓冲区是否有任何优势性能,明智的。如果不是(我猜想,事实并非如此),那么你就不需要担心如何正确清理。
4. 如果你用完的GC会自动触发。但是,如果你用完了GC的,则不会触发(在Sun的JVM,至少),你只得到一个OutOfMemoryError错误即使GC会释放我发现你必须在这种情况下手动触发GC。 一个更好的解决方案可能是对的ByteBuffer所以你永远不需要重新acllocate的ByteBuffers。
5. 要释放的直接Buffer的[1]的内存,你的JNI。 该函数GetDirectBufferAddress(JNIEnv* env, jobject buf)[3]从JNI 6的API可以获取指针的Buffer然后在标准free(void *ptr)命令上的指针自由 而不是编写如C代码从Java调用该函数,你JNA的Native.getDirectBufferPointer(Buffer)[6] 之后剩下的唯一一件事就是放弃了所有引用Buffer对象。那么Java的垃圾回收将释放Buffer例如,因为它与任何其它非引用的对象。 请注意,直接Buffer不一定映射1:1到一个区域中。例如JNI的API有NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity)[7]。因此,你应该只Buffer你知道是一对一的跟的,分配区域 我也不知道,如果你可以free直接Buffer通过Java的创建ByteBuffer.allocateDirect(int)[8]为完全如上述的理由。当交给了新的直接也可能是JVM或Java平台的具体细节是否泳池或做1:1的内存分配Buffer秒。 这里遵循从我的图书馆就直接稍加修改的片段ByteBuffer[9]处理(使用JNANative[10]和Pointer[11]类):
/**
* Allocate native memory and associate direct {@link ByteBuffer} with it.
*
* @param bytes - How many bytes of memory to allocate for the buffer
* @return The created {@link ByteBuffer}.
*/
public static ByteBuffer allocateByteBuffer(int bytes) {
long lPtr = Native.malloc(bytes);
if (lPtr == 0) throw new Error(
"Failed to allocate direct byte buffer memory");
return Native.getDirectByteBuffer(lPtr, bytes);
}
/**
* Free native memory inside {@link Buffer}.
* <p>
* Use only buffers whose memory region you know to match one to one
* with that of the underlying allocated memory region.
*
* @param buffer - Buffer whose native memory is to be freed.
* The class instance will remain. Don't use it anymore.
*/
public static void freeNativeBufferMemory(Buffer buffer) {
buffer.clear();
Pointer javaPointer = Native.getDirectBufferPointer(buffer);
long lPtr = Pointer.nativeValue(javaPointer);
Native.free(lPtr);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值