Java中的热切垃圾收集

时间:2012-06-28 07:57:02

标签: java garbage-collection jvm

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

我确实理解垃圾收集的概念,我知道堆中总会有一定数量的死对象,但是,我想最小化这个数量,以便用JConsole(或JVisualVM)监视向我提供了有关当前所需(未占用)空间的一些信息。

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

澄清

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

另外:我说的是在开发人员测试期间使用,而不是在生产中使用。在制作中,传播和表演当然比更现实的记忆足迹更重要。

4 个答案:

答案 0 :(得分: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空间。如果是这样,您需要知道对象的平均寿命。并遵循一些最佳实践,然后进行精细调整。另请注意,发出System.gc()并不能保证GC已执行。

事实是实例转到young generation (eden),当它已满时,执行minor GC。仍可到达的对象将传递给名为survivor的两个空格之一。一旦满了,该空间就会被转储到tenured。完整后,full GC执行并删除所有无法访问的实例。

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

有用的参数是那些与ternured and young generation (eden)的大小相关的参数。这些按比例工作。如果您要考虑许多GC,请设置GC stop的最长时间。

一些有趣的参数是:

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

例如,设置-XX:NewRatio=3意味着年轻一代与老一代的比例为1:3;换句话说,伊甸园和幸存者空间的总和将是堆的四分之一。

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

答案 1 :(得分:0)

您可以在启动Java应用程序时传递-Xgenconfig标志。您可以阅读更多相关信息here

来自网站的引用:

  

genconfig开关可用于指定堆的大小   明确的年轻人和老年人。它也允许老一代   要指定的收集器。 (genconfig选项生成-Xms和   -Xmx选项不必要,但如果与genconfig一起使用选项-Xmx仍然被认为是一个   意味着限制旧一代堆大小。)

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

答案 2 :(得分:0)

虽然确实有一种方法可以将GC子系统配置为比默认值更具攻击性,但在所有可能性中,您都会意识到您正在努力将代码转向零垃圾。标准Java库几乎完全依赖于快速访问短期对象的每一步。例如字符串连接,增强的循环,自动装箱等等。

答案 3 :(得分:0)

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

使用此功能,您将能够为您的应用找到旧版本的最小尺寸,然后您就可以开始为年轻一代尝试不同的尺寸。

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

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