Java应用程序通过JNI调用C++ DLL; 如何最好地分配内存?

Jos*_*hDM 7 c++ java memory dll java-native-interface

问题的基本摘要是:如何最好地优化我的内存分配,以便为我通过JNI访问的DLL提供尽可能多的内存?我应该尽量减少什么,我应该最大化什么,等等.

SYSTEM:在具有4 GB RAM的32位系统中将JBoss 6作为Windows 32服务运行.我确实理解Java Heap的内存有最大限制.JVM是JRE1.6.0_26

服务:安装在JBoss下的是一个接收客户请求的webapp; 每个请求通过JNI调用C++构建的DLL来以某种方式处理图像文件.

问题:有时,对于较大的或一些(并非所有)LZW压缩映像,调用java类会收到DLL遇到全局内存耗尽并且无法完成请求的进程的消息.

除了基本的Windows进程之外,服务器上没有其他活动正在运行.

当前的JBOSS App Server内存设置如下,但可能过多:

-Xms1024m -Xmx1024m -Xss1024k -XX:MaxPermSize = 128m

我正在尝试确定最佳内存设置,以便为JNI DLL提供尽可能多的资源,因为据我所知,JNI不使用分配给Java堆的任何内存.

我已阅读这些内容,但没有发现它们对回答我的问题有帮助:

Java JNI:内存分配/分区

可以使用jconsole来识别JNI C++对象中的内存泄漏吗?

目前提供的两个答案没有解决遗留问题.

一周后JBoss服务器的当前内存与JVM参数设置如上(TaskManager指示java.exe进程为750,672k)

Total Memory Pools: 5

Pool: Code Cache (Non-heap memory)

    Peak Usage : init:2359296, used:7317312, committed:7438336, max:50331648
    Current Usage : init:2359296, used:7306496, committed:7438336, max:50331648


        |---------| committed:7.09Mb
        +---------------------------------------------------------------------+
        |/////////| | max:48Mb
        +---------------------------------------------------------------------+
        |---------| used:6.97Mb


Pool: PS Eden Space (Heap memory)

    Peak Usage : init:268500992, used:354811904, committed:354811904, max:355991552
    Current Usage : init:268500992, used:270153472, committed:354091008, max:354156544


        |--------------------------------------------------------------------| committed:337.69Mb
        +---------------------------------------------------------------------+
        |///////////////////////////////////////////////////// || max:337.75Mb
        +---------------------------------------------------------------------+
        |----------------------------------------------------| used:257.64Mb


Pool: PS Survivor Space (Heap memory)

    Peak Usage : init:44695552, used:44694896, committed:78643200, max:78643200
    Current Usage : init:44695552, used:0, committed:1835008, max:1835008


        |---------------------------------------------------------------------| committed:1.75Mb
        +---------------------------------------------------------------------+
        | | max:1.75Mb
        +---------------------------------------------------------------------+
        | used:0b


Pool: PS Old Gen (Heap memory)

    Peak Usage : init:715849728, used:123671968, committed:715849728, max:715849728
    Current Usage : init:715849728, used:104048648, committed:715849728, max:715849728


        |---------------------------------------------------------------------| committed:682.69Mb
        +---------------------------------------------------------------------+
        |////////// | max:682.69Mb
        +---------------------------------------------------------------------+
        |---------| used:99.23Mb


Pool: PS Perm Gen (Non-heap memory)

    Peak Usage : init:16777216, used:91989664, committed:134217728, max:134217728
    Current Usage : init:16777216, used:90956472, committed:90963968, max:134217728


        |----------------------------------------------| committed:86.75Mb
        +---------------------------------------------------------------------+
        |//////////////////////////////////////////////| | max:128Mb
        +---------------------------------------------------------------------+
        |----------------------------------------------| used:86.74Mb
Run Code Online (Sandbox Code Playgroud)

all*_*eek 11

由JNI包装的本机代码分配的内存分配给JVM进程,但不受Java代码的控制.它不是堆的一部分,并且不能通过JVM参数进行调整.基本上,使用本机malloc分配的任何内容都必须由该本机代码管理.如果您掌控所使用的库,则必须通过它并检查资源是否泄漏.如果在长期使用过程中使用它,这一点尤为重要.

根据我的经验,最好的方法是通过拉动JVM公开的JMX统计数据来检查实际的内存使用情况.一旦您了解了Java应用程序消耗了多少内存,您就可以更好地了解设置最大堆设置的位置.Permgen空间用于类定义等,所以除非你正在做一堆动态类加载,否则你真的不需要太多内存.

虽然您无法调整可用于JNI库的内存,但调整为堆保留的内存等可能会释放资源以供库使用.

正如所预料的那样,将堆内存峰值加在一起就会出现大约1022.19(堆的最大大小).当堆耗尽时,将启动完整的GC运行并回收脏堆.根据您提供的数字,我建议从Xmx512m开始.这将为您的JNI代码室提供呼吸.

如果您发现JVM由于过多的垃圾收集而发生颠簸,这意味着您的Java堆耗尽过快,您可以增加该分配.但是,如果它足够快地消耗512mb以引起明显的性能影响,那么不太可能没有任何显着增加会产生很大影响.这一切都在很大程度上取决于您的程序,它吃Java堆的速度以及完整GC运行的效率.

  • 进程堆的"其他所有"部分包括:Permenent Space,代码生成,套接字缓冲区,线程堆栈,直接内存空间,JNI代码,垃圾收集和JNI分配的内存.因此,虽然减法会给你这个空间的总和,它不仅会成为JNI分配的空间(尽管那可能是它最大的消费者). (2认同)
  • 好吧,还有其他参数可以帮助您调整Java堆使用情况,但这些参数是最重要的.我会稍微运用你的代码来确定典型的堆栈占用量并分配+ 30-40%并将其设置为最大堆大小.因为你只想使用你需要的内存,所以我会把Xms保留为默认设置,除非你看到错误的地方,你特别耗尽了Permgen空间,我也会留下它.除非你在这里运行一个大型的多线程应用程序,否则我也会单独留下Xss.这里的重要人物是Xmx(最大堆大小). (2认同)