繁体   English   中英

Java 堆转储:如何通过 1.io.netty.buffer.ByteBufUtil 2.byte[] 数组找到占用 memory 的对象/类

[英]Java Heap Dump : How to find the objects/class that is taking memory by 1. io.netty.buffer.ByteBufUtil 2. byte[] array

我发现我的一个 spring 引导项目的 memory (RAM consumption) 每天都在增加。 当我将 jar 文件上传到 AWS 服务器时,它占用了 582 MB 的 RAM(最大分配的 RAM 为 1500 MB),但是每天,RAM 都在增加 50 MB 到 100 MB,今天 5 天后,它占用了 835 MB . 目前该项目有 100-150 个用户,正常使用 Rest 个 API。

由于 RAM 的增加,应用程序多次出现以下错误(从日志中发现的错误):

Exception in thread "http-nio-3384-ClientPoller" java.lang.OutOfMemoryError: Java heap space

所以为了解决这个问题,我发现通过使用 JAVA 堆转储,我可以找到占用 memory 的对象/类。所以通过在命令行中使用Jmap ,我创建了一个堆转储并将其上传到Heap HeroEclipse Memory 分析工具 在他们两个中,我发现了以下内容:

1. Total Waste memory 是:64.69MB (73%)(查看下面的截图)

在此处输入图像描述

2 . 其中,34.06MB 被Byte [] arrayLinkedHashmap[] (检查下面的屏幕截图)占用,我从未在我的整个项目中使用过它们。 我在我的项目中搜索它但没有找到。

在此处输入图像描述 3 . 以下 2 个大对象分别占用 32 MB 和 20 MB。

1. Java Static io.netty.buffer.ByteBufUtil.DEFAULT_ALLOCATOR

2. Java Static com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.connectionFinalizerPhantomRefs` 

在此处输入图像描述

所以我试图找到this.netty.buffer。 在我的项目中,但我找不到任何与.netty 或缓冲区匹配的内容。

现在我的问题是如何减少此 memory 泄漏如何找到确切的 memory 消费对象/类/变量,以便减少堆大小。

我知道很少有专家会要求源代码或类似的东西,但我相信从堆转储中我们可以找到 memory 泄漏或 memory 中可用的活动对象 我正在寻找该选项或任何可以减少此堆转储的选项!

在过去的 3 周里,我一直在研究这个问题。 任何帮助,将不胜感激。 谢谢你!

从启用JVM 本机 memory 跟踪器开始,通过添加标志-XX:NativeMemoryTracking=summary了解 memory 的哪一部分正在增加。 根据文档,有一些性能开销 (5-10%),但如果这不是问题,我建议即使在生产中也启用此标志运行 JVM。

然后您可以使用jcmd <PID> VM.native_memory检查值(此答案中有一篇很好的文章: Java native memory usage

如果确实分配了一大块本机 memory,则很可能这是由 Netty 分配的。

您如何在 AWS 中运行您的应用程序? 如果它在 Docker 映像中运行,您可能会偶然发现这个问题: 什么会导致 java 进程大大超过 Xmx 或 Xss 限制? 在这种情况下,如果您的应用程序使用本机 memory(Netty 使用)并在具有大量内核的服务器上运行,则可能需要设置环境变量MALLOC_ARENA_MAX 很可能 JVM 为 Netty 分配了这个 memory 但没有看到任何释放它的理由,所以它看起来只会继续增长。

如果你想控制 Netty 可以分配多少本机 memory,你可以为此使用 JVM 标志-XX:MaxDirectMemorySize (我相信默认值与Xmx相同)并降低它以防你的应用程序不需要这么多 memory。

JVM memory 调整是一个复杂的过程,当涉及本机 memory 时,它变得更加复杂 - 正如链接的答案所示,它不像简单地设置XmsXmx标志并期望不再使用 memory 那样简单。

堆转储不足以检测 memory 泄漏。 您需要查看调用 GC 后拍摄的两个连续堆快照的区别。 或者您需要一个分析工具,可以为每个 class 提供世代计数。然后您应该只查看在 GC 中幸存下来并从旧快照传递到新的一个。 或者,如果使用分析工具,寻找仍然存在并成长了很多代的旧域对象。

让对象存在多代并不断增长意味着这些对象仍然被引用并且 GC 无法回收它们。 但是,仅仅活了很多代还不足以造成泄漏,因为缓存或 static 对象可能会停留很多代。 另一个重要因素是它们不断增长。

在检测到 object 被泄漏后,您可以使用 heap dumb 来分析这些对象并获取引用。

暂无
暂无

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

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