Al *_*inn 11 java 64-bit jvm jvm-arguments
我正在努力解决Java应用程序的大内存需求.
为了解决更多内存,我已经切换到64位JVM并使用大型xmx.但是,当xmx高于2GB时,应用程序似乎比预期更早耗尽内存.当运行xmx为2400M并查看GC信息时,-verbosegc
我得到...
[Full GC 2058514K->2058429K(2065024K), 0.6449874 secs]
Run Code Online (Sandbox Code Playgroud)
...然后它会抛出一个内存不足的异常.我希望它在内存不足之前将堆增加到2065024K以上.
在一个简单的例子中,我有一个测试程序,它在循环中分配内存并打印出信息Runtime.getRuntime().maxMemory()
,Runtime.getRuntime().totalMemory()
直到它最终耗尽内存.
在一系列xmx值上运行它会显示Runtime.getRuntime().maxMemory()
报告比xmx少10%,并且总内存不会增长超过90%Runtime.getRuntime().maxMemory()
.
我使用以下64位jvm:
java version "1.6.0_26" Java(TM) SE Runtime Environment (build 1.6.0_26-b03) Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)
这是代码:
import java.util.ArrayList;
public class XmxTester {
private static String xmxStr;
private long maxMem;
private long usedMem;
private long totalMemAllocated;
private long freeMem;
private ArrayList list;
/**
* @param args
*/
public static void main(String[] args) {
xmxStr = args[0];
XmxTester xmxtester = new XmxTester();
}
public XmxTester() {
byte[] mem = new byte[(1024 * 1024 * 50)];
list = new ArrayList();
while (true) {
printMemory();
eatMemory();
}
}
private void eatMemory() {
// TODO Auto-generated method stub
byte[] mem = null;
try {
mem = new byte[(1024 * 1024)];
} catch (Throwable e) {
System.out.println(xmxStr + "," + ConvertMB(maxMem) + ","
+ ConvertMB(totalMemAllocated) + "," + ConvertMB(usedMem)
+ "," + ConvertMB(freeMem));
System.exit(0);
}
list.add(mem);
}
private void printMemory() {
maxMem = Runtime.getRuntime().maxMemory();
freeMem = Runtime.getRuntime().freeMemory();
totalMemAllocated = Runtime.getRuntime().totalMemory();
usedMem = totalMemAllocated - freeMem;
}
double ConvertMB(long bytes) {
int CONVERSION_VALUE = 1024;
return Math.round((bytes / Math.pow(CONVERSION_VALUE, 2)));
}
}
Run Code Online (Sandbox Code Playgroud)
我使用此批处理文件在多个xmx设置上运行它.它包括对32位JVM的引用,我想要与32位jvm进行比较 - 显然这个调用在xmx大于1500M时就会失败
@echo off
set java64=<location of 64bit JVM>
set java32=<location of 32bit JVM>
set xmxval=64
:start
SET /a xmxval = %xmxval% + 64
%java64% -Xmx%xmxval%m -XX:+UseCompressedOops -XX:+DisableExplicitGC XmxTester %xmxval%
%java32% -Xms28m -Xmx%xmxval%m XmxTester %xmxval%
if %xmxval% == 4500 goto end
goto start
:end
pause
Run Code Online (Sandbox Code Playgroud)
这会吐出一个csv,当放入excel时看起来像这样(在这里为我糟糕的格式道歉)
32位
XMX max mem total mem free mem %of xmx used before out of mem exception 128 127 127 125 2 98.4% 192 191 191 189 1 99.0% 256 254 254 252 2 99.2% 320 318 318 316 1 99.4% 384 381 381 379 2 99.5% 448 445 445 443 1 99.6% 512 508 508 506 2 99.6% 576 572 572 570 1 99.7% 640 635 635 633 2 99.7% 704 699 699 697 1 99.7% 768 762 762 760 2 99.7% 832 826 826 824 1 99.8% 896 889 889 887 2 99.8% 960 953 953 952 0 99.9% 1024 1016 1016 1014 2 99.8% 1088 1080 1080 1079 1 99.9% 1152 1143 1143 1141 2 99.8% 1216 1207 1207 1205 2 99.8% 1280 1270 1270 1268 2 99.8% 1344 1334 1334 1332 2 99.9%
64位
128 122 122 116 6 90.6% 192 187 187 180 6 93.8% 256 238 238 232 6 90.6% 320 285 281 275 6 85.9% 384 365 365 359 6 93.5% 448 409 409 402 6 89.7% 512 455 451 445 6 86.9% 576 512 496 489 7 84.9% 640 595 595 565 30 88.3% 704 659 659 629 30 89.3% 768 683 682 676 6 88.0% 832 740 728 722 6 86.8% 896 797 772 766 6 85.5% 960 853 832 825 6 85.9% 1024 910 867 860 7 84.0% 1088 967 916 909 6 83.5% 1152 1060 1060 1013 47 87.9% 1216 1115 1115 1068 47 87.8% 1280 1143 1143 1137 6 88.8% 1344 1195 1174 1167 7 86.8% 1408 1252 1226 1220 6 86.6% 1472 1309 1265 1259 6 85.5% 1536 1365 1317 1261 56 82.1% 1600 1422 1325 1318 7 82.4% 1664 1479 1392 1386 6 83.3% 1728 1536 1422 1415 7 81.9% 1792 1593 1455 1448 6 80.8% 1856 1650 1579 1573 6 84.8% 1920 1707 1565 1558 7 81.1% 1984 1764 1715 1649 66 83.1% 2048 1821 1773 1708 65 83.4% 2112 1877 1776 1769 7 83.8% 2176 1934 1842 1776 66 81.6% 2240 1991 1899 1833 65 81.8% 2304 2048 1876 1870 6 81.2% 2368 2105 1961 1955 6 82.6% 2432 2162 2006 2000 6 82.2%
Ste*_*n C 13
为什么会这样?
基本上,JVM/GC可以使用两种策略来决定何时放弃并抛出OOME.
它可以继续前进和前进,直到垃圾收集后没有足够的内存来分配下一个对象.
它可以继续运行,直到JVM花费超过运行垃圾收集器的给定百分比的时间.
第一种方法存在的问题是,对于典型应用程序,JVM将花费越来越多的时间来运行GC,最终完成任务的徒劳无功.
第二种方法存在问题,即它可能会过早放弃.
此区域中GC的实际行为由JVM选项(-XX:...)控制.显然,默认行为在32位和64位JVM之间有所不同.这种方式是有道理的,因为(直观地)64位JVM的"内存不足死亡螺旋"效应将持续更长时间并且更加明显.
我的建议是单独留下这个问题.除非你真的需要用内容填充每个内存的最后一个字节,否则JVM最好早点死掉并避免浪费大量时间.然后,您可以使用更多内存重新启动它并完成工作.
显然,您的基准是非典型的.大多数真正的程序根本不会尝试抓住所有堆.您的应用程序可能也是非典型的.但是,您的应用程序也可能遭受内存泄漏.如果是这种情况,你应该调查泄漏,而不是试图找出你不能使用所有内存的原因.
但是我的问题主要是为什么它不尊重我的xmx设置.
它很荣幸!-Xmx是堆大小的上限,而不是决定何时放弃的标准.
我已经设置了2432M的XMX,但要求JVM返回其对最大内存返回2162M的理解.
它返回它使用的最大内存,而不是允许使用的最大内存.
为什么它"认为"最大内存比xmx低11%?
往上看.
此外,为什么当堆命中2006M时它没有将堆扩展到至少2162?
我认为这是因为JVM已经达到了"花费太多时间来收集垃圾"的门槛.
这是否意味着在64位JVM中,应该将XMX设置捏造为比预期最大值高11%?
不一般.软糖因素取决于您的应用.例如,具有较大对象流失率的应用程序(即,每单位有用工作创建和丢弃更多对象)可能会更快地与OOME一起死亡.
我可以根据数据库大小预测需求,并有一个调整xmx的包装器,但是我有11%的问题,我的montioring建议应用程序需要2 GB,所以我设置了2.4GB xmx.然而,jvm不仅没有预期的400MB"净空",而且只允许堆增长到2006M.
IMO,解决方案是在您目前添加的内容之上添加额外的 20%(或更多).假设您有足够的物理内存,为JVM提供更大的堆将减少整体GC开销并使您的应用程序运行得更快.
您可以尝试的其他技巧是将-Xmx和-Xms设置为相同的值并调整设置最大"垃圾收集时间"比例的调整参数.
归档时间: |
|
查看次数: |
5728 次 |
最近记录: |