我有一个应用程序,它将一些数据放入一个长链接列表中,占用JVM中几乎所有的JVM内存。当插入一个新元素时,最后一个元素将被删除,因此列表的大小总是一个常量。当我将JVM内存大小设置为6GB时,我开始得到规则的GC暂停:3.4秒,大约每10秒发生一次。
我在Linux上使用Hotspot Java 1.7.0,64位,它有4核和16 on内存。传递以下JVM参数:-Xmx6g -XX:+PrintGC -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
请您提供一些更好的选项,将GC暂停时间减少到大约100毫秒左右。我试着自己寻找这样的选择,但没有成功。
资料来源如下:
LinkedList<long[]> list = new LinkedList<long[]>();
// initial fill in
for(int i = 0; i < 16L*1024*1024; i ++) {
list.add(new long[16]);
}
System.out.printf("total: %5.1f free: %5.1f\n",((float)Runtime.getRuntime().totalMemory())/(1024*1024*1024), ((float)Runtime.getRuntime().freeMemory())/(1024*1024*1024));
// the main stuff
for(;;) {
list.removeFirst();
list.add(new long[16]);
}更新:在下面的讨论中,我意识到人们试图对代码进行一些修改。因此,我需要更多地解释这个问题的背景。源示例是一个合成的不真实代码。它很好地说明了许多旧的gen对象的问题。我遇到这个问题时,我试图实现一个高度加载的缓存解决方案,其中有一些插入和驱逐策略。这常常导致旧一代垃圾的问题。我在这里的目标是使用JVM选项找到最好的解决方案。在这里,我不想考虑代码改进。我假设,如果有一种神奇的GC参数组合,这使得我的示例能够处理100 my以下的暂停,它也可能解决更一般的问题,或者至少为类似的情况提供一些提示。
发布于 2013-07-15 13:36:03
我会尝试用ArrayDequeue替换可怕的链接列表,特别是考虑到队列大小是恒定的。
非常长的链接列表会导致垃圾收集器的性能问题,因为垃圾收集器是递归实现标记的。收集器可能更喜欢使用可以迭代标记的大型数组。
更新
有一个模糊的GC调优参数可能有帮助:
如果您使这个参数更大,如果标记是深度递归的(因为它可能是针对一个巨大的链接列表),那么阻止CMS收集器切换到非增量模式就足够了。
但是,这样做会增加JVM的总体内存使用量。我的“信封背面”的想法是,要用16M元素标记链接列表,就需要在至少192兆字节的范围内标记一个标记堆栈。这需要乘以进行标记的GC线程的数量。
我问题的目标不是修改Java代码。想象一下,您有一个正确的java程序,它不会导致OutOfMemoryError。您必须在不更改代码的情况下找到正确的JVM参数。实际上,我了解这种暂停的原因,只是不知道如何对JVM进行调优,使暂停小于100 to。
我担心在这种情况下,你的目标很可能是无法实现的(不能承受上述)。如果应用程序对GC非常不友好,那么GC性能就会很差。
无论如何,你的更大的目标是(应该)用任何必要的方法来解决性能问题。把程序修好。在这种情况下,修复也可能有其他好处;例如,减少内存使用。
发布于 2013-07-16 07:26:51
我正在开发一个名为香蕉的原始集合库,它支持原语链接列表。您的用例--它是香蕉闪闪发光的理想用例,但它可以做得更多(包括可变长度块,您没有使用它,但可能在您的真实世界中使用)。
这是我的计算机上的基准测试的结果:
Banana : 1269 ms elapsed
Banana : total: 2.5 GB, free: 0.5 GB, used = 2.1 GB, Banana reports that it's actually using 2.1 GB
Java : 13543 ms elapsed
Java : total: 6.2 GB, free: 2.0 GB, used = 4.2 GB你可以看到香蕉速度更快,内存也更少。(如果不首先运行香蕉函数,Java内存就会更好
Java : 14426 ms elapsed
Java : total: 5.8 GB, free: 1.9 GB, used = 3.9 GB但仍然没有靠近香蕉。
package net.yadan.banana.list;
public class LinkedListBenchmark {
public static void main(String[] args) {
banana();
java();
}
public static void banana() {
long t = System.currentTimeMillis();
// initial list size 16m records, block size 32 (storage is int[], so we
// need 32 ints to hold 16 longs)
net.yadan.banana.list.LinkedList list = new LinkedList(16 * 1024 * 1024, 16 * 2, 0);
// initial fill in
for (int i = 0; i < 16L * 1024 * 1024; i++) {
list.appendTail(32); // similar to java list.add() which appends to the
// end of the list
}
// the main stuff
for (int i = 0; i < 16L * 1024 * 1024; i++) {
list.removeHead(); // similar to java list removeFirst()
list.appendTail(32); // similar to java list.add() which appends to the
// end of the list
}
System.out.println("Banana : " + (System.currentTimeMillis() - t) + " ms elapsed");
float GB = 1024 * 1024 * 1024;
long total = Runtime.getRuntime().totalMemory();
long free = Runtime.getRuntime().freeMemory();
System.out
.printf(
"Banana : total: %5.1f GB, free: %5.1f GB, used = %5.1f GB, Banana reports that it's actually using %5.1f GB\n",
total / GB, free / GB, (total - free) / GB, list.computeMemoryUsage() / GB);
}
public static void java() {
long t = System.currentTimeMillis();
java.util.LinkedList<long[]> list = new java.util.LinkedList<long[]>();
// initial fill in
for (int i = 0; i < 16L * 1024 * 1024; i++) {
list.add(new long[16]);
}
// the main stuff
for (int i = 0; i < 16L * 1024 * 1024; i++) {
list.removeFirst();
list.add(new long[16]);
}
System.out.println("Java : " + (System.currentTimeMillis() - t) + " ms elapsed");
float GB = 1024 * 1024 * 1024;
long total = Runtime.getRuntime().totalMemory();
long free = Runtime.getRuntime().freeMemory();
System.out.printf("Java : total: %5.1f GB, free: %5.1f GB, used = %5.1f GB\n", total / GB, free / GB,
(total - free) / GB);
}
}发布于 2013-07-18 13:39:29
对于大多数垃圾收集器来说,您的例子几乎就是病态的例子。解决这个问题的一个更好的方法是使用Disruptor,但是我从您的评论中看到,您不想要替代的设计建议。
如果您提供了一个GC日志,可能会有一些CMS调优选项来使事情变得更好,但是没有日志很难判断。停顿是由于FullGC引起的,还是由于备注阶段引起的?如果是FullGC,可能是CMS启动的时间不够早,无法跟上进度。
你真正要解决的问题是什么,因为这个设计的问题看起来有点疯狂?
如果您想拥有这样的设计模式,那么最好的JVM就是Azul。
https://stackoverflow.com/questions/17654964
复制相似问题