问题的基本概要是: 如何最好地优化内存分配,为我通过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
答案 0 :(得分:11)
由JNI包装的本机代码分配的内存被分配给JVM进程,但不受Java代码的控制。它不是堆的一部分,并且不能通过JVM参数进行调整。基本上,使用本机malloc分配的任何内容都必须由该本机代码管理。如果您掌控所使用的库,则必须通过它并检查资源是否泄漏。如果在长期使用过程中使用它,这一点尤其重要。
根据我的经验,最好的方法是通过拉动JVM公开的JMX统计数据来检查实际的内存使用情况。一旦您了解了Java应用程序消耗了多少内存,您就可以更好地了解设置最大堆设置的位置。 Permgen空间用于类定义等,所以除非你正在进行一堆动态类加载,否则你真的不需要那么大的内存。
虽然您无法调整可用于JNI库的内存,但调整为堆保留的内存可能会释放资源以供库使用。
正如预期的那样,将堆内存峰值一起添加到大约1022.19(堆的最大大小)。当堆耗尽时,将启动完整的GC运行并回收脏堆。根据您提供的数字,我建议从Xmx512m开始。这将为您的JNI代码室提供呼吸。
如果您发现JVM由于过多的垃圾收集而发生颠簸,这意味着您的Java堆快速耗尽,那么您可以增加该分配。但是,如果它足够快地消耗512mb以引起明显的性能影响,那么任何不显着增加的东西都不会产生太大影响。这一切都在很大程度上取决于您的程序,它吃Java堆的速度,以及完整GC运行的效率。