如何分析老年代内存碎片化?是否有相关工具可用?
滞后情况每小时发生一次。大多数时间它们持续约20秒,但有时会持续几分钟。
Oracle网站上的了解并发标记清除垃圾收集器日志页面应该有助于解释GC日志。
最后,楼主得出这是一个“碎片化”问题的结论是不太可能的,并且(在我看来)不受他提供的证据片段支持。很可能是其他原因。
如果您需要进行低级监控,您需要使用-XX:PrintFLSStatistics=1
(或者将其设置为2以获得更多的阻塞成本)。它是未记录的,有时会给出一些统计数据。不幸的是,由于不同的原因,它在大多数应用程序中并不是非常有用,但至少可以提供参考。
例如,您应该能够看到:
Max Chunk Size: 215599441
并将其与此进行比较
Total Free Space: 219955840
这是一个比较难找到的问题。因为我花了一些时间在系统中找到并证明,让我列出发生这种情况的场景。
表现出来的问题是,我们系统中只有一个特定的算法运行缓慢;同时运行的其他所有算法都正常运行。这排除了Full GC;此外,我们使用jstat和其他j **工具来检查GC、线程转储+跟踪GC日志。
从一段时间内获取的jstack线程转储中,我们可以得到一个想法,哪个代码块真正地减慢了速度。所以怀疑落在了堆碎片上。
为了测试,我编写了一个简单的程序,初始化了两个列表,一个是ArrayList,另一个是LinkedList,并进行了添加操作以引起调整大小。我可以通过REST处理程序执行此测试。 通常没有太大的区别。但在碎片化堆内部,时间上有明显的差异;使用ArrayList进行大型集合调整大小比使用LinkedList要慢得多。这些时间已被记录下来,除了碎片化头之外,没有其他解释。我曾经使用YourKit来解决这种类型的问题,效果很好。
Java中不存在内存碎片; 在GC运行期间,内存区域会被压缩。
由于您没有看到高CPU利用率,因此也没有GC运行。因此,其他原因必须是导致问题的原因。以下是一些想法:
如果应用程序的数据库位于不同的服务器上,则可能存在网络问题
如果您运行Windows并且已映射网络驱动器,则其中一个驱动器可能会锁定计算机(再次是网络问题)。对于Unix上的NFS驱动器也是如此。检查系统日志以获取网络错误。
计算机是否将大量数据交换到磁盘?由于CPU利用率低,问题的原因可能是应用程序被交换到磁盘,而GC运行强制将其推回RAM。如果您的服务器没有足够的真实RAM来保持整个Java应用程序在RAM中,则这将需要很长时间。
此外,其他进程可能会强制将应用程序移出RAM。检查实际内存利用率和交换空间使用情况。
要理解GC日志的输出,this post 可能会有所帮助。
[编辑] 我仍然无法理解“低CPU”和“GC停顿”。这两者通常是相互矛盾的。如果GC停顿,您必须看到100%的CPU使用率。如果CPU处于空闲状态,则其他某些内容会阻止GC。您是否有超载finalize()
的对象?如果finalize阻塞,则GC可能需要很长时间。