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

时间:2011-10-08 23:33:04

标签: java c++ memory dll java-native-interface

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

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

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

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

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

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

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

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

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

Java JNI : Memory allocation / partitioning

Can jconsole be used to identify memory leaks in JNI C++ objects?

目前提供的两个答案并未解决遗留问题。

一周后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

1 个答案:

答案 0 :(得分:11)

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

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

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

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

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