为什么JVM不使用堆内存

时间:2014-06-10 09:19:40

标签: java garbage-collection jvm

我试图像这样增加堆内存:

-Xmx9g -Xms8g

说实话,只因为我可以。

现在我想知道为什么JVM不会使用更多,并且不太频繁地调度GC。

Heap Usage Graph

系统:
JVM:Java HotSpot(TM)64位服务器VM(24.51-b03,混合模式)
Java:版本1.7.0_51,供应商Oracle Corporation

修改
我想改进我的建模过程配置(吞吐量击败响应)。

2 个答案:

答案 0 :(得分:4)

Java 1.7中的HotSpot JVM separates the heap into a few spaces以及此讨论的相关内容是:

  • 伊甸园,新物品在哪里
  • 幸存者,如果他们需要在伊甸园事件发生后需要物品,

当您分配新对象时,它只是简单地附加到Eden空间中。一旦伊甸园已满,它就会被称为“未成年人”的小集合。"伊甸园中仍然可以到达的物体被复制到幸存者,然后擦除伊甸园(因此收集任何未被复制的物体)。

你想要的是填充伊甸园,而不是整个堆。

例如,拿这个简单的应用程序:

public class Heaps {
  public static void main(String[] args) {
    Object probe = new Object();
    for (;;) {
      Object o = new Object();
      if (o.hashCode() == probe.hashCode()) {
        System.out.print(".");
      }
    }
  }
}

probe就是为了确保JVM能够优化循环;重复的new Object()实际上就是我们所追求的。如果使用默认的JVM选项运行它,您将获得一个类似于您所看到的图形的图形。对象分配在Eden上,这只是整个堆的一小部分。一旦Eden已满,它就会触发一个次要集合,它会清除所有这些新对象并将堆使用量降低到其基线,#34;接近0。

那么,你如何填满整个堆?设置伊甸园非常大! Oracle发布了heap tuning parameters,其中两个相关的是-XX:NewSize-XX:MaxNewSize。当我用-Xms9g -XX:NewSize=8g -XX:MaxNewSize=8g运行上述程序时,我得到的东西更接近你的预期。

enter image description here

在一次运行中,这几乎耗尽了所有堆,以及我指定的所有Eden空间;后续的运行只占我指定的Eden的一小部分,正如你在这里看到的那样。我不太清楚为什么会这样。

VisualVM有一个名为Visual GC的插件,可以让您查看有关堆的更多详细信息。这是我的一个屏幕截图,在恰当的时刻拍摄,显示Eden几乎已满,而旧空间几乎是空的(因为环中的new Object()没有一个能够存活Eden系列)。 / p>

enter image description here

答案 1 :(得分:3)

(我将尝试在这里以不同的角度回答"为什么"的问题。)

通常,您希望使用GC设置平衡两件事:吞吐量和响应能力。

吞吐量取决于GC整体花费的时间,响应度取决于各个GC运行的长度。确定默认GC设置以在两者之间给出合理的折衷。

高吞吐量意味着长时间测量GC开销会更少。 另一方面,高响应性将使得一小段代码更有可能在大致相同的时间内运行,并且不会被GC持续很长时间。

如果您调整GC参数以允许填充所有9GB的堆,您可以发现吞吐量可能已经增加(虽然我不确定它总是会这样)但是当GC最终运行,您的应用程序冻结几秒钟。对于运行单个长时间运行计算但不适用于HTTP服务器的进程而言,这可能是可以接受的,对于桌面应用程序则更是如此。

故事的寓意是:你可以调整你的GC以做你想做的任何事情,但除非你得到一个你诊断出的特定问题(正确),否则你可能最终会比默认设置。

更新:由于您似乎希望获得高吞吐量但不会对暂停感到困扰,因此您最好的选择是使用吞吐量收集器(-XX:+ UseParallelGC)。我显然无法为您提供确切的参数,您必须使用this guide通过观察每个更改的效果来调整它们。 我可能不需要告诉你这个,但我的建议是一次改变一个参数,然后检查它对性能的影响。