调试奇怪的内存泄漏 - Java/Tomcat

vic*_*pos 6 java tomcat memory-leaks

我在Tomcat下运行的Java应用程序遇到了一个非常奇怪的问题.

我们尝试从一个为期一周的sprint中重新生成的新产品更新生产代码,该应用程序已运行数月而没有打嗝,然后这个新代码使我们的Linux服务器在一段时间后开始交换.

非常奇怪的是,当查看VisualVM的内存使用情况时,它永远不会超过最大堆大小,JVM不会抛出OutOfMemory,机器只会启动交换,JVM会在此之后继续运行.

所以,它似乎从某个地方泄漏了内存,看起来它来自新代码,但奇怪的是它不在JVM中,任何关于如何调试的想法?

谢谢!

Apo*_*sia 4

交换并不是泄漏的决定性指标。这是由于物理内存不足造成的。在 Linux 上使用 vmstat 来获取交换空间使用情况。尝试使用不同的机器,尝试配置——交换大小、物理内存大小、地址空间。

如果您确信问题出在您的程序中,请尝试以下操作:

  1. 估计您的程序应使用的内存中值和峰值。您必须能够解释与这些指标的所有偏差。如果不能,请继续执行步骤 3。

  2. 假设您正确执行了步骤 1,并且能够解决所有偏差,您就可以排除泄漏(很抱歉出现如此模糊的建议,但调试效果取决于侦探)。您现在应该专注于 GC 调优。首先,启用 GC 日志记录。查看堆是否确实已满,以及 GC 大部分时间都花在哪里进行收集。可能是开始优化的一个很好的起点。尝试看看调整 GC 选项是否有帮助。尝试尝试收集算法、最大/最小堆大小、生成比率等。仅在排除泄漏后才进行实验(步骤 1)。

  3. 假设您正确执行了步骤 1 并且无法解释所有偏差,则可以假设某处存在泄漏。使用内存分析器查看哪些对象对堆大小增长影响最大。让探查器长时间运行——让你的程序处理一些它通常期望收到的请求,然后让它相对隔离。如果内存水平持续增长,则可能在某个地方发生泄漏。如果不是,则可能不是内存泄漏。你能指出你的程序中可能创建它们的部分吗?如果是,请尝试发送多个仅针对程序的该部分的请求。它是否确定性地复制了问题?如果不是,请重复步骤 3。如果是,请使用分治法并重新应用步骤 3,直到找到罪魁祸首的类/方法。它也可以是多个部分的某种组合(这意味着它们单独看起来可能是无辜的,但它们组合在一起可能会形成一个出色的犯罪集团)。

希望这对您有所帮助,如果没有,请在我的帖子中发表评论。

祝您锻炼一切顺利!