当前位置: 首页 > 面试题库 >

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

酆乐湛
2023-03-14
问题内容

我们的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)

VM选项包括:

-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进入“内存不足”状态(永久保存),就对它进行了堆转储,并在其上运行了Eclipse Memory Analyzer。

结果很有趣。大约200Mb的空间被各种对象占用(有些对象拥有比其他对象更多的内存),但是其余的1.9Gb都无法到达(也许值得注意的是,大多数对象都被GSON对象占用,但是我不认为这是表示一切,仅表示在服务器运行期间我们经过了许多GSON对象)。

关于VM为什么有这么多无法访问的对象并且根本无法收集它们的任何解释?

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]

解决了

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

我仍然认为JVM的行为是一个谜。看起来垃圾收集器陷入了停滞状态,将不再清理更多的内存,但是内存分配器希望将其清除(因此不会引发OOM)。相反,我希望它清除所有无法访问的内存。但是应用程序的行为不会好很多,因为大部分时间还是会花费在垃圾收集上。

我用于帮助的代理可以在这里找到:https :
//github.com/veselov/MethodCountAgent。它远非完美的软件。


问题答案:

关于VM为什么有这么多无法访问的对象并且根本无法收集它们的任何解释?

(根据我们在评论中的交流),这听起来像不是传统的内存泄漏,而是某种逻辑在不断地向新对象发送垃圾邮件,从而使GC难以跟上当前的体系结构。

罪魁祸首可能是例如多次发出很多API请求,或者以某种错误状态“卡住”,例如我描述的无限分页方案。两种情况都归结为实例化了数百万个响应gson对象(指向Strings(指向char[]s)),然后可以使用GC。

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



 类似资料:
  • 本文向大家介绍Java遍历对象可访问的对象(堆1.0),包括了Java遍历对象可访问的对象(堆1.0)的使用技巧和注意事项,需要的朋友参考一下 示例            

  • 我使用jmap使用CMS GC转储应用程序的实时堆: 我用YourKit打开了这个转储,它发现8Gb堆的61%是不可访问的,特别是 我以为使用意味着它只包含可访问的对象? 总司令。应用程序的日志文件可疑地缺少由我调用jmap引起的任何完整GC,而是在我进行转储的两侧显示以下行: 在堆转储完成后第一次CMS重置后的第一个ParNew集合中,我看到堆的大小大致与堆转储中的大小相同(大约3-4Gb):

  • 我正在努力解决一个奇怪的问题。 控制台是 如您所见,第一行输出了GeneratorField对象的名称,但是为什么第二个命令失败了? 我正在使用Freemarker 2.3.20 谢啦

  • 因此,我正在构建一种基于对象的模型方法,并试图将所有现有的jQuery转换为纯JavaScript调用,但我遇到了一些问题。 所以我有一个基本的基础: 由于某些原因,当使用jQuery调用时,它都运行得很好,但是当使用Document.QuerySelector调用JS替代项时,我会得到一个错误,如下所示: 谁能给我解释一下.find()调用和传统JS的主要区别是什么?

  • 我正在尝试创建一个连接四的GUI。 我有一个类Gui,它创建了一个板(一个数组[][]ints)和一个方法move,它接受player(int)和column(int)以及一个检查是否有赢家的方法。 我用gridLayout创建了一个gui,我有一行按钮和7个JLabel数组(这是一个空槽的ImageIcon)。如果玩家选择了一个特定数组的最下面的JLabel列,我现在需要访问该列。 我在一个循环

  • 我不确定我是不是漏了一步。 我有一个s3 bucket,我需要能够从一个AWS SDK PHP脚本访问我写的运行在我的EC2上。我创建了一个IAM角色以允许访问。 IAM Allow_S3_Access_to_EC2 我的Bucket策略中没有任何关于我的EC2甚至我附加的IAM角色的内容。我也需要在我的桶策略中添加一些东西吗?这就是我困惑的地方。 我所经历的是,当一个新的对象被创建,我试图从我的