我有很长的 GC 周期。从检查中我看到堆的永久(旧)区域中有太多对象。是否有任何实用程序可以知道哪些对象位于堆的哪个区域,或者关于这些对象的任何静态信息。
我正在使用 Sun/Oracle HotSpot JVM (Java 6)。
编辑:关于我的问题的更多细节:
我有一个大堆(32GB),看起来即使堆旧区域只有 30% 已满,手动运行 GC 也会暂停 15 秒。我想知道哪些对象是留在旧区的“幸存者”,以便知道要优化哪个对象创建。
我有很长的 GC 周期。从检查中我看到堆的永久(旧)区域中有太多对象。是否有任何实用程序可以知道哪些对象位于堆的哪个区域,或者关于这些对象的任何静态信息。
我正在使用 Sun/Oracle HotSpot JVM (Java 6)。
编辑:关于我的问题的更多细节:
我有一个大堆(32GB),看起来即使堆旧区域只有 30% 已满,手动运行 GC 也会暂停 15 秒。我想知道哪些对象是留在旧区的“幸存者”,以便知道要优化哪个对象创建。
我不知道有任何工具/实用程序适用于当前一代 JVM。
但另一方面是我看不到这样的实用程序会有什么帮助。
很长的 GC 时间通常是因为你的堆太满了。随着堆接近 100% 满,在 GC 中花费的时间往往呈指数增长。在最坏的情况下,堆完全填满,你的应用程序会得到一个OutOfMemoryError
. 有两种可能的解决方案:
如果根本原因是堆太小(对于您的应用程序试图解决的问题的大小),那么要么增加堆大小,要么寻找减少应用程序工作集的方法;即在计算过程中它需要“活”的对象的数量/大小。
如果根本原因是内存泄漏,则查找并修复它。
在这两种情况下,使用内存分析器都可以帮助您分析问题。但是你不需要知道老年代中有哪些对象。它与问题的根本原因或问题的解决方案无关。
我想知道哪些对象是留在旧区的“幸存者”,以便知道要优化哪个对象创建。
这开始变得更有意义了。听起来您需要找出哪些对象是长期存在的……而不是具体地确定它们所在的空间。您可以通过jhat
比较一系列堆快照来做到这一点。(可能有更好的方法......)
但是,我仍然认为这种方法不会有帮助。问题是完整的 GC 需要遍历所有可到达的(硬、软、弱、幻)对象。而且,如果您有一个 32Gb 堆已满 30%,那么您仍然有很多对象需要标记/清除/重定位。我认为解决方案可能是使用并发收集器并对其进行调整,以便它可以跟上应用程序的对象分配率。
听起来您可能会System.gc()
直接从您的代码中调用。 不要那样做! 调用System.gc()
将(通常)导致 JVM 进行完整的垃圾回收。这几乎可以保证让你停下来。让 JVM 决定何时运行收集器要好得多。
最后,不清楚“优化对象创建”是什么意思。你的意思是降低对象创建率?或者您是否正在考虑其他方法来管理长期(缓存?)对象的保留?
工具大象跟踪可以分析对象的创建和死亡,大象跟踪。有了这个,你也许能够弄清楚什么样的对象比预期的存活时间更长,并且通过方法历史,有可能得到精确的对象。
但是大堆意味着非常长的配置文件时间和非常大的配置文件文件。
我从未见过允许“探索”给定一代中的对象的工具。
我习惯于 Netbeans Profiler。它不能真正做到你所要求的,但它有一个工具可以让你知道出了什么问题。
使用 Profiler 运行应用程序,选择Memory
,然后在Live Results
您的列Generations
中。它没有告诉您每个对象的生成,但它为您提供了Surviving Generations
. 因此,如果该数字大于 1,则它可能在终身(可能在幸存者空间)中,如果该数字一直在增长,则您有内存泄漏。
我认为没有任何实用程序可以告诉您不同代的对象数量。
jconsole
jdk附带的。在 jconsole 的帮助下,您可以连接到您的应用程序并监视所有代,在这里您可能会得到一些我不确定的数字。jmap
,然后对其进行分析。MAT
JVM
参数运行您的应用程序,并在日志中获得有关 GC 的信息GC logging is enabled using JVM arguments; below are the arguments I use. (Note: the log file specified as file is reset each time the VM starts.
-verbose:gc -Xloggc:file
我认为这可能对你有帮助。