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

问题的基本摘要是:如何最好地优化我的内存分配,以便为我通过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 

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

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

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

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

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