繁体   English   中英

如何分析java中的内存碎片?

[英]How to analyze memory fragmentation in java?

我们的服务器经历了几分钟的滞后。 可能它们是由“停止世界”垃圾收集引发的。 但我们使用并发标记和扫描GC(-XX:+ UseConcMarkSweepG),所以,我认为,这些暂停是由旧一代的内存碎片触发的。

如何分析老一代的记忆碎片? 它有什么工具吗?

每小时发生一次陷阱。 大多数时间他们大约20秒,但有时 - 几分钟。

查看Java文档中的“java -X ...”选项以打开GC日志记录。 这将告诉您是否正在收集旧的或新的一代,以及收集的时间。

暂停“几分钟”听起来非同寻常。 您确定不仅仅是运行堆大小太小,还是在物理内存不足的机器上运行?

  • 如果您的堆太接近满,GC将一次又一次地触发,导致您的服务器在GC中花费大部分CPU时间。 这将显示在GC日志中。

  • 如果在物理内存不足的计算机上使用大堆,则完整的GC可能会导致计算机“崩溃”,花费大部分时间疯狂地将虚拟内存页移入和移出光盘。 您可以使用系统监控工具观察到这一点; 例如,在典型的UNIX / Linux系统上观看“vmstat 5”的控制台输出。

跟进

与OP的观点相反,打开GC记录不太可能对性能产生明显的影响。

Oracle站点上的Understanding Concurrent Mark Sweep Garbage Collector Logs页面应该有助于解释GC日志。

最后,OP的结论是这是一个“碎片化”的问题是不可能的,并且(IMO)没有得到他提供的证据片段的支持。 它很可能是别的东西。

对于低级别监视,您将需要使用此-XX:PrintFLSStatistics=1 (或以更多阻塞成本将其设置为2)。 它没有记录,偶尔会给你一些统计数据。 不幸的是,由于不同的原因,它在大多数应用程序中并不是很有用,但它至少是有用的。

你应该能够看到例如

Max Chunk Size: 215599441

并将其与此进行比较

Total Free Space: 219955840

然后根据平均块大小和块数判断碎片。

我已经使用YourKit来解决这类问题。

维塔利,有碎片问题。 我的观察:如果对象的小尺寸经常更新,那么在这种情况下会产生大量垃圾。 虽然CMS收集这些对象占用的内存,但这个内存是碎片化的。 现在Mark-Sweep-Compact线程进入画面(停止世界)并试图压缩这个碎片化的内存导致长时间停顿。

与此相反,如果对象大小较大,则会产生较少碎片的内存和
Mark-Swap-Compact缩短了这个内存所需的时间。 这可能会导致吞吐量降低,但可以帮助您减少GC压缩造成的长时间停顿。

这是一个难以找到的问题。 由于我花了一些时间在系统中找到并证明这一点,让我列出发生这种情况的情景

  • 我们坚持使用Java 6,它没有任何压缩的垃圾收集器
  • 我们的应用程序做了太多GC主要是年轻一代的收藏和一些老一代的收藏
  • 我们的堆大小是一个非常大的主要问题(我们减少了,但是我们的应用程序在太多的字符串和集合上花了很多钱)

显而易见的问题是我们系统中只有一个特定算法运行缓慢; 其余所有同时运行的,运行正常。 这排除了Full GC; 我们还使用jstat和其他j **工具来检查GC,线程转储+尾随GC日志。

从jstack线程转储,花了一段时间,我们可以了解哪个代码块真的在减速。 所以怀疑是堆积碎片。

为了测试我写了一个简单的程序,初始化了两个List一个ArrayList和一个LinkedList,并添加了导致调整大小的操作。 我可以通过REST句柄执行此测试。 通常没有太大区别。 但是在一个零碎的堆中,时间上有明显的差异; 使用ArrayList重新调整大集合变得非常慢,而不是使用Linked列表。 记录了这些时间,除了碎片化的头部之外没有其他解释。

在Java 7中,我们转向了G1GC,以及GC调优和改进应用程序的大量工作; 这里堆压缩要好得多,它可以处理更大的堆,但我想任何超过16克的堆都会让你落到你真不想去的地方 - GC suckage :)

要了解Vitaly如何处理此问题,请参阅了解并发标记扫描垃圾收集器日志

Java中没有内存碎片; 在GC运行期间,内存区域被压缩。

由于您没有看到高CPU利用率,因此也没有GC运行。 所以别的东西必然是你问题的原因。 以下是一些想法:

  • 如果应用程序的数据库位于其他服务器上,则可能存在网络问题

  • 如果您运行Windows并且已映射网络驱动器,则其中一个驱动器可能会锁定您的计算机(再次出现网络问题)。 Unix上的NFS驱动器也是如此。 检查系统日志中的网络错误。

  • 计算机是否将大量数据交换到磁盘? 由于CPU util低,问题的原因可能是应用程序被交换到磁盘并且GC运行强制它返回到RAM。 如果您的服务器没有足够的实际RAM来将整个Java应用程序保存在RAM中,则需要很长时间。

此外,其他进程可以强制应用程序退出RAM。 检查实际内存利用率和交换空间使用情况。

要了解GC日志的输出, 这篇文章可能有所帮助。

[编辑]我仍然无法理解“低CPU”和“GC档位”。 这两者通常相互矛盾。 如果GC停止运行,您必须看到100%的CPU使用率。 如果CPU空闲,则其他东西阻止GC。 你有过载finalize()对象吗? 如果一个finalize阻止,GC可以永远。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM