3

我想更好地了解我的应用程序,特别是它的内存占用。

我确实了解垃圾收集的概念,并且我知道,堆中总会有一定数量的死对象,但是,我想尽量减少这个数量,以便使用 JConsole(或 JVisualVM)进行监控为我提供有关当前所需(未占用)空间的一些信息。

有没有办法在 SunVM 中配置现有的垃圾收集器(例如 G1GC),以便(以响应和运行时为代价)最小化堆中的死对象数量?

澄清

为了更清楚我的目标:我的应用程序是非交互式的,因此随着时间的推移,内存占用量在两次运行之间或多或少是相同的。我想确定所需的最小堆空间以及代码更改对该占用空间的影响。由于死对象,JConsole 的输出在这里并没有真正的帮助。我也想知道,我的峰值记忆是否真的是某个时间点的一个突出的峰值,或者它是否随着时间的推移而被拉长。这就是为什么在我达到 OOME 之前减少 Xmx 并不是让我到达那里的原因。

另外:我说的是在开发人员测试期间的使用,而不是在生产中的使用。在生产中,吞吐量和性能 - 当然 - 比更现实的内存占用更重要。

4

4 回答 4

5

如果您想知道您的应用程序正在使用的内存总量,您必须监视它相当长的时间。应用程序随机时刻的堆样本:

jps -> output the pid of java process
jmap -dump:live,format=b,file=heap.bin [pid]

然后jhat导航堆。还有其他工具可以做到这一点。

这样做你会立刻知道堆上有什么。

请记住,诸如此类的对象memory mapped files不存储在堆中,而是存储在内存中。

到达时OOM尝试添加它,然后读取输出以查看哪些对象实际上在堆中:

-XX:-HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./java_pid<pid>.hprof

为此,请启用GC log并使用诸如GCViewer 之类的工具。

-XX:+PrintGCTimeStamps
 -XX:+PrintGCDetails
-verbose:gc
-Xloggc:garbage_collector -> this set the file of the output

当您谈论堆时,我知道您在谈论tenured空间。如果是这样,您需要知道对象的平均寿命。并遵循一些最佳实践,然后进行微调。还要记住,发出 aSystem.gc()并不能保证GC执行了。

事情是实例去young generation (eden)并且当它充满时minor GC执行。仍然可以访问的对象被传递到称为 的两个空间之一survivor。一旦这个空间被填满,空间就会被转储到tenured. 当已满时,afull GC会执行并删除所有无法访问的实例。

您可以做的一件事是primitives在方法中使用。那些不会放在堆中,因为它们的生命周期在线程堆栈中。

有用的参数是那些与tenured and young generation (eden). 这些按比例起作用。如果您要发出许多问题,请GC记住为GC stop.

一些有趣的参数是:

-XX:MinFreeHeapRatio=  
-XX:MaxHeapFreeRatio=  
-XX:NewRatio=
-XX:SurvivorRatio

例如,设置-XX:NewRatio=3表示年轻代和老年代的比例为1:3;换句话说,伊甸园和幸存者空间的组合大小将是堆的四分之一。

无论如何,我不知道你为什么需要这个要求。我通常只担心并且只在不好throughput时才关心这些参数。throughput

于 2012-06-28T08:04:58.217 回答
0

-Xgenconfig您可以在启动 Java 应用程序时传递标志。你可以在这里阅读更多关于它的信息。

引自网站:

genconfig 开关可用于明确指定年轻代和年老代的堆大小。它还允许指定老年代收集器。(genconfig 选项使 -Xms 和 -Xmx 选项变得不必要,但如果与 genconfig 选项一起使用,-Xmx 仍然被认为是限制老一代堆大小的一种手段。)

通过指定较小的堆大小,GC 会更频繁地触发。我相信这正是您正在寻找的。

于 2012-06-28T08:03:01.283 回答
0

虽然肯定有一种方法可以将 GC 子系统配置为比默认设置更具侵略性,但您很可能会意识到您正在与试图将您的代码扭曲到零垃圾的潮流作斗争。标准 Java 库几乎每一步都依赖于短期对象的快速 gc-ing。示例是简单的字符串连接、增强的 for 循环、自动装箱等。

于 2012-06-28T08:03:40.580 回答
0

是的,这是可能的,但这取决于您的应用程序在做什么。您只能通过试验和启用 GC 日志来找到这个答案。

使用它,您将能够为您的应用找到老年代的最小尺寸,然后您可以开始为年轻一代尝试不同的尺寸。

  • 更小的年轻代意味着更频繁的收集,但内存占用更小
  • 更大的一代将意味着更少的收集频率,但更大的内存占用

请注意,如果年轻代太小,对象可能会在老年代过早提升,而无法满足其生命周期要求。当您看到更多完整的 GC 集合时,您可以检测到这一点。

于 2012-06-28T08:18:52.633 回答