Java 堆被无法访问的对象淹没

2024-04-18

我们的 Java EE 应用程序开始出现一些严重问题。具体来说,应用程序在启动后几分钟内就运行了高达 99% 的老年代堆。不会抛出 OOM,但实际上 JVM 没有响应。 jstat 显示老年代的大小根本没有减少,没有垃圾收集正在进行,并且kill -3 说:

Heap
 PSYoungGen      total 682688K, used 506415K [0xc1840000, 0xf3840000, 0xf3840000)
  eden space 546176K, 92% used [0xc1840000,0xe06cd020,0xe2da0000)
  from space 136512K, 0% used [0xe2da0000,0xe2da0000,0xeb2f0000)
  to   space 136512K, 0% used [0xeb2f0000,0xeb2f0000,0xf3840000)
 PSOldGen        total 1536000K, used 1535999K [0x63c40000, 0xc1840000, 0xc1840000)
  object space 1536000K, 99% used [0x63c40000,0xc183fff8,0xc1840000)

虚拟机选项有:

-Xmx2300m -Xms2300m -XX:NewSize=800m -XX:MaxNewSize=800m -XX:SurvivorRatio=4 -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+UseParallelGC -XX:ParallelGCThreads=4 

(我将其从 2300m 堆/1800m 新一代更改为尝试解决问题)

一旦 JVM 进入“内存不足”状态(持续很长时间),我就对 JVM 进行堆转储,并在其上运行 Eclipse Memory Analyzer。

结果很有趣。大约 200Mb 被各种对象占用(有些对象比其他对象拥有更多),但其余的 1.9Gb 都是无法访问的(可能值得注意的是,大部分被 GSON 对象占用,但我不认为这是任何事情的指示,只是说我们在服务器操作期间搅动了大量 GSON 对象)。

有什么解释可以解释为什么虚拟机有这么多无法访问的对象,并且根本无法收集它们吗?

JVM:

$ /0/bin/java -version
java version "1.6.0_37"
Java(TM) SE Runtime Environment (build 1.6.0_37-b06)
Java HotSpot(TM) Server VM (build 20.12-b01, mixed mode)

当系统到达这个停顿状态时,以下是详细 GC 不断打印的内容:

922.485: [GC [1 CMS-initial-mark: 511999K(512000K)] 1952308K(2048000K), 3.9069700 secs] [Times: user=3.91 sys=0.00, real=3.91 secs] 
926.392: [CMS-concurrent-mark-start]
927.401: [Full GC 927.401: [CMS927.779: [CMS-concurrent-mark: 1.215/1.386 secs] [Times: user=5.84 sys=0.13, real=1.38 secs] (concurrent mode failure): 511999K->511999K(512000K), 9.4827600 secs] 2047999K->1957315K(2048000K), [CMS Perm : 115315K->115301K(262144K)], 9.4829860 secs] [Times: user=9.78 sys=0.01, real=9.49 secs] 
937.746: [Full GC 937.746: [CMS: 512000K->511999K(512000K), 8.8891390 secs] 2047999K->1962252K(2048000K), [CMS Perm : 115302K->115302K(262144K)], 8.8893810 secs] [Times: user=8.89 sys=0.01, real=8.89 secs] 

SOLVED

正如 Paul Bellora 所言,这是由于在太短的时间内在 JVM 中创建的对象数量过多造成的。此时调试变得相当乏味。我最终所做的是,使用自定义 JVM 代理来检测类。该检测将对方法和构造函数调用进行计数。然后检查计数。我发现一个不起眼的单个操作会创建大约 200 万个对象,并触发某些单独的方法大约 150 万次(不,没有循环)。与其他操作相比,该操作本身的速度较慢。您也可以使用任何热点分析器(例如 VisualVM),但我在这些方面遇到了各种麻烦,所以最终编写了自己的热点分析器。

我仍然认为 JVM 的行为是一个谜。看起来垃圾收集器陷入停滞,并且不会再清理任何内存,但内存分配器希望它这样做(因此不会抛出 OOM)。相反,我希望它能够清除所有无法访问的内存。但应用程序的行为也不会好多少,因为无论如何大部分时间都会花在垃圾收集上。

我用来寻求帮助的代理可以在这里找到:https://github.com/veselov/MethodCountAgent https://github.com/veselov/MethodCountAgent。它距离一个完美的软件还很远。


有什么解释可以解释为什么虚拟机有这么多无法访问的对象,并且根本无法收集它们吗?

(根据我们在评论中的交流)听起来这不是传统的内存泄漏,而是一些不断向新对象发送垃圾邮件的逻辑,使得 GC 在当前架构下难以跟上。

例如,罪魁祸首可能是某个多次发出的 API 请求,或者“卡在”某种错误状态,如我描述的无限分页场景。这两种情况归结为数百万个响应 gson 对象(指向Strings(指向char[]s)) 被实例化,然后有资格进行 GC。

正如我所说,您应该尝试隔离问题请求,然后进行调试并进行测量,以确定这是否是您的应用程序或其库之一的错误或可扩展性问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 堆被无法访问的对象淹没 的相关文章

随机推荐

  • Android 上的 Pyzbar 不读取 QR 码,但读取条形码

    我一直在使用 pyzbar 开发一个 kivy 应用程序 在需要读取条形码和 QR 码的 Android 上运行 该应用程序可以读取我电脑上运行的条形码和 QR 码 但在使用使用 buildozer 构建的 apk 时无法读取 QR 码 但
  • 使用 PDF 框旋转 pdf 内容而不旋转页面或 PDF

    我正在使用 PDFBOX 1 8 目前 如果 PDF 处于横向模式 则将其旋转为纵向模式 如下所示 public static byte rotatePDF byte inputPdf throws Exception PDDocument
  • 如何获取当年的总周数?

    我在 stackoverflow 上得到了下面的代码 它返回当年的总周数 但它是硬编码的 在 2014 年和 2016 年不起作用 我如何动态获取当年的总周数 Calendar cal Calendar getInstance cal se
  • Javascript Google Maps API 和非被动事件处理程序

    最近 Chrome 开始发出以下警告 违规 向滚动阻塞 touchmove 事件添加了非被动事件侦听器 考虑将事件处理程序标记为 被动 以使页面响应更快 看https www chromestatus com feature 5745543
  • 当应用程序在 Firebase 后台运行时如何处理通知

    这是我的清单
  • has_many 与总活跃记录

    class Product lt ActiveRecord Base belongs to category has many order items dependent destroy end class OrderItem lt Act
  • 以编程方式嵌入 Java h2 数据库

    目前我们使用HSQLDB http www hsqldb org 作为嵌入式数据库 但随着数据量的增长 我们会寻找内存占用更少的数据库 德比 JavaDB http developers sun com javadb 目前不是一个选项 因为
  • 如何从年、月、日获取日期对象?

    当我使用以下代码时 Date对象错误 Date date new Date day getYear day getMonth day getDay 谁能告诉我如何从年 月 日的值中获取日期对象 您可以使用Calendar类来实现这一点 pu
  • 宏 $(VCTargetsPath) 到底在哪里定义的?

    我们之前有过讨论 https social msdn microsoft com Forums vstudio en US e04e7791 c0c4 4598 b900 310878f5af45 how can i locate and
  • 我们可以更新 Amazon S3 中特定文件的内容吗?

    我正在使用AWS PHP SDK 我将 JSON 文件上传到 S3 存储桶 现在我想获取文件内容 上传到S3存储桶 向抓取的文件内容添加一些附加文本并通过 S3 存储桶更新该文件 我想要的是这样的 文件名 userlist json 使用
  • wagtail 中的嵌套类别/InlinePanel

    我很难实现 嵌套类别 之类的东西 PageA Cat1 SubCat1 SubCat2 Cat2 SubCat1 所有类别和子类别都应可由编辑排序和编辑 我的猜测是这样的 class CategoryTestPage Page conten
  • lucene:如何添加不重复的文档

    就我而言 插入 lucene 索引的每个文档都有其唯一的 ID 当向lucene索引添加新文档时 如果该文档已经存在于索引中 则不应将该文档插入到索引中 如何实施这一战略 我想我应该先用docId搜索文档 如果lucene找不到该文档 那么
  • 如何在 Android 上对 XML 进行编码?

    我需要将 XML 文档编码为一种格式 该格式将作为字符串 即条带标签 通过 XML 解析器 然后我需要再次解码它 并且我需要在 Android 上执行此操作 我正在寻找的 Android API 中的库 类是什么 Thanks XmlSer
  • 运行我的应用程序时,Java 运行时环境检测到致命错误

    我在运行程序时遇到以下错误 并且无法弄清楚解决方案是什么我还查看了具有类似错误的所有主题 但无法解决我的问题 这里的错误 我的应用程序是基于 Groovy 和 Grails 版本 2 0 4 构建的 A fatal error has be
  • 使用 bash 通过 ssh 启动进程,然后在 sigint 上终止它

    我想使用 ssh 在不同的机器上启动几个作业 如果用户随后中断主脚本 我想优雅地关闭所有作业 这是我正在尝试做的事情的一个简短示例 bin bash trap aborted SIGINT SIGTERM aborted kill SIGT
  • 每个键的填充数据帧和累积度量 Pandas

    我有以下数据框 import pandas as pd before padding pd DataFrame data user id 1 1 1 1 2 2 3 days past 1 2 3 4 2 3 2 pay 11 12 13
  • tesseract (v3.03) 输出为 PDF [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 为什么会返回这个错误呢 root amd 3700 2gb ocr test tesseract l dan pdf png out pd
  • 无法加载动态库'C:\php\ext\php_pthreads.dll'

    我试图在我的 php 代码中添加线程 但我无法理解pthreads库 每次运行程序时都会遇到此错误 Warning PHP Startup Unable to load dynamic library C php ext php pthre
  • 通过多种方法进行 Spring JPA 事务

    我在 Tomcat 7 中运行的 Web 应用程序中使用带有 JPA 和 Hibernate 4 的 Spring 3 2 该应用程序分为控制器 服务和 DAO 类 服务类在类和方法级别具有带注释的事务配置 DAO 是普通的 JPA 带有通
  • Java 堆被无法访问的对象淹没

    我们的 Java EE 应用程序开始出现一些严重问题 具体来说 应用程序在启动后几分钟内就运行了高达 99 的老年代堆 不会抛出 OOM 但实际上 JVM 没有响应 jstat 显示老年代的大小根本没有减少 没有垃圾收集正在进行 并且kil