我正在研究一个时间关键的应用程序,每次迭代的时间上限为40毫秒。如果仅超过一次时间上限,则终止应用程序并结束游戏。应用程序本身在40毫秒标记下没有任何问题,垃圾收集器有时会超出限制。
使用对象池结合工厂模式,我成功地消除了对垃圾收集的需求,并且应用程序实现了稳定的17 ms迭代时间,包括小型GC运行,除了在应用程序启动后的10到20次迭代之外单个完整GC发生超过40毫秒并杀死我的应用程序。
我的问题是,如何分析导致这一个完整GC的确切原因?我使用jvisualvm密集地描述我的运行时和内存占用,这对于识别我需要缓存的对象是一个很好的帮助。但是在这种特殊情况下我无法使用它,因为在我按下jvisualvm中的右键之前很久就会出现完整的GC。 有没有办法以编程方式生成堆转储?
答案 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)
答案 2 :(得分:1)
JVM上的垃圾收集在大多数情况下都是一个巨大的优势,但主要的缺点(正如您所确定的)是它有时会导致不可预测的GC暂停。
标准JVM适用于软实时(当您可以容忍偶尔的暂停时)但不适合硬实时(即超出给定容差的任何暂停导致错误/失败)
一些有用的建议是:
答案 3 :(得分:1)
您可以尝试jprofiler的评估版,它可让您让应用等待分析器启动。它不会影响堆内存,它通常是一个强大的分析器,具有良好的IDE集成和一键设置。
但是既然你说你无法控制堆大小或gc设置,那么你就无法做到。在启动时加载类会产生一些需要收集的垃圾。
我可能会问:这是家庭作业还是某种竞赛/挑战?
答案 4 :(得分:0)
您是否尝试过调整垃圾回收参数?如果您的计算机具有足够的RAM和多个核心,那么您应该能够利用并行垃圾收集。这是enabled by default on Java 1.6 JVMs。基本上,如果你确保年轻一代足够大,那么对象永远不会被提升为旧的(这是连续收集的)。