4

我正在开发一个时间紧迫的应用程序,每次迭代的时间上限为 40 毫秒。如果仅超过一次时间上限,则应用程序终止并结束游戏。应用程序本身保持在 40 毫秒以下没有问题,有时是垃圾收集器超过了限制。

使用对象池与工厂模式相结合,我设法在很大程度上消除了垃圾收集的需要,并且应用程序实现了稳定的 17 毫秒迭代时间,包括小型 GC 运行,除了应用程序启动后的 10 到 20 次迭代仅一次完整 GC发生超过 40 毫秒并终止我的应用程序。

我的问题是,我如何分析究竟是什么导致了这个完整的 GC?我大量使用 jvisualvm 来分析我的运行时和内存占用情况,这对识别我需要缓存的对象很有帮助。但在这种特殊情况下,我不能使用它,因为在我按下 jvisualvm 中的正确按钮之前很久就会发生完整的 GC。有没有办法以编程方式生成堆转储?

4

5 回答 5

3

我会使用像 YourKit 这样的商业内存分析器。您可以从其中大部分获得足够长的免费评估许可证来解决您的问题。;)

我发现 VisualVM 的一个问题是,当您最小化对象创建时,最大的内存生产者是 Memory Profiler 本身。商业分析器没有这个问题,因为它们使用堆外内存。

我想看看你能做些什么来进一步减少你的垃圾。17 毫秒仍然很长,您也可以考虑对 CPU 进行分析。CPU 分析器在大约半毫秒内很有用。低于此值,您需要使用自己的精确时间和一些试验和错误。

我发现有用的是在完成 CPU 配置文件和内存配置文件之后,同时运行它们,你会得到更多关于你可以改进的建议。

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

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

于 2012-09-02T12:24:16.093 回答
1

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

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

一些有用的建议是:

  • 如果可以的话,转移到专门的实时 JVM(例如Zing JVM)。这是使用 Java 可靠地获得实时行为的最佳方式
  • 使用低延迟库,例如Javolution - 通过提供具有非常低的对象分配率的数据结构(因此减少 GC 开销),这些库可以提供很大帮助
于 2012-09-02T12:28:28.517 回答
1

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

但是由于您说您无法控制堆大小或 gc 设置,因此您无能为力。在启动时加载类会产生一些需要收集的垃圾。

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

于 2012-09-02T12:44:03.457 回答
1

你听说过 HeapDumpOnCtrlBreak; 试试这个链接

或替代地使用

jmap -dump:format=b,file=<filename.hprof> <pid>
于 2012-09-02T12:14:54.680 回答
0

您是否尝试过调整垃圾收集参数?如果您在一台具有足够 RAM 和多个内核的机器上,那么您应该能够利用并行垃圾收集。它在 Java 1.6 JVMs 上默认启用。基本上,如果您确保年轻一代足够大,以至于对象永远不会被提升到老一代(以串行方式收集)。

于 2012-09-02T12:45:49.897 回答