在Java中分析和避免使用Full GC

时间:2012-09-02 12:09:17

标签: java performance garbage-collection

我正在研究一个时间关键的应用程序,每次迭代的时间上限为40毫秒。如果仅超过一次时间上限,则终止应用程序并结束游戏。应用程序本身在40毫秒标记下没有任何问题,垃圾收集器有时会超出限制。

使用对象池结合工厂模式,我成功地消除了对垃圾收集的需求,并且应用程序实现了稳定的17 ms迭代时间,包括小型GC运行,除了在应用程序启动后的10到20次迭代之外单个完整GC发生超过40毫秒并杀死我的应用程序。

我的问题是,如何分析导致这一个完整GC的确切原因?我使用jvisualvm密集地描述我的运行时和内存占用,这对于识别我需要缓存的对象是一个很好的帮助。但是在这种特殊情况下我无法使用它,因为在我按下jvisualvm中的右键之前很久就会出现完整的GC。 有没有办法以编程方式生成堆转储?

5 个答案:

答案 0 :(得分:3)

我会使用像YourKit这样的商业内存分析器。您可以从大部分时间获得免费的eval许可证,以解决您的问题。 ;)

我在VisualVM中发现的一个问题是,当你最小化对象创建时,最大的内存生成器就是Memory Profiler本身。商业分析器没有这个问题,因为他们使用了堆内存。

我会看到你可以做些什么来进一步减少你的垃圾。 17 ms仍然很长时间,你也可以考虑使用CPU分析。 CPU分析器可用到大约半毫秒。如果低于此值,您需要使用自己的精确计时和一些反复试验。

我发现有用的东西是在执行CPU配置文件和内存配置文件之后,立即运行它们,您会得到更多关于可以改进的建议。

如果减少产生的垃圾量并增加伊甸园空间,您可能每天只能获得一次小型收集。

http://vanillajava.blogspot.co.uk/2011/06/how-to-avoid-garbage-collection.html

答案 1 :(得分:1)

你听说过HeapDumpOnCtrlBreak; Try this link

或者使用

jmap -dump:format=b,file=<filename.hprof> <pid>

答案 2 :(得分:1)

JVM上的垃圾收集在大多数情况下都是一个巨大的优势,但主要的缺点(正如您所确定的)是它有时会导致不可预测的GC暂停。

标准JVM适用于软实时(当您可以容忍偶尔的暂停时)但不适合硬实时(即超出给定容差的任何暂停导致错误/失败)

一些有用的建议是:

  • 如果可以,请转到专门的实时JVM(例如Zing JVM)。这是使用Java可靠地获取实时行为的最佳方法
  • 使用低延迟的libarries,例如Javolution - 通过提供具有非常低的对象分配率(因此减少GC开销)的数据结构,这些可以提供很多帮助。

答案 3 :(得分:1)

您可以尝试jprofiler的评估版,它可让您让应用等待分析器启动。它不会影响堆内存,它通常是一个强大的分析器,具有良好的IDE集成和一键设置。

但是既然你说你无法控制堆大小或gc设置,那么你就无法做到。在启动时加载类会产生一些需要收集的垃圾。

我可能会问:这是家庭作业还是某种竞赛/挑战?

答案 4 :(得分:0)

您是否尝试过调整垃圾回收参数?如果您的计算机具有足够的RAM和多个核心,那么您应该能够利用并行垃圾收集。这是enabled by default on Java 1.6 JVMs。基本上,如果你确保年轻一代足够大,那么对象永远不会被提升为旧的(这是连续收集的)。