Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaGC:旧一代变得越来越大,无法回收_Java_Garbage Collection - Fatal编程技术网

JavaGC:旧一代变得越来越大,无法回收

JavaGC:旧一代变得越来越大,无法回收,java,garbage-collection,Java,Garbage Collection,我正在编写我的servlet程序,并使用jconsole和jmap来监视它的内存状态。我发现当我的程序运行时,内存池“PS Old Gen”变得越来越大,最后我的servlet无法响应任何请求 这是我的JConsole输出的快照: 当我点击“执行GC”按钮时,什么也没发生 因此,为了查看详细信息,我使用jmap转储详细信息: 这是我的JConsole VM摘要输出: 任何人都可以帮助我找出问题所在?您知道,GC“PS MarkSweep”和“PS cleave”是我的服务器JVM的默认GC

我正在编写我的servlet程序,并使用jconsole和jmap来监视它的内存状态。我发现当我的程序运行时,内存池“PS Old Gen”变得越来越大,最后我的servlet无法响应任何请求

这是我的JConsole输出的快照:

当我点击“执行GC”按钮时,什么也没发生

因此,为了查看详细信息,我使用jmap转储详细信息:

这是我的JConsole VM摘要输出: 任何人都可以帮助我找出问题所在?您知道,GC“PS MarkSweep”和“PS cleave”是我的服务器JVM的默认GC

多谢各位


我发现一个很奇怪的现象:从昨天18:00到今天09:00的15个小时内,“PS Old Gen”上的GC似乎从未发生过,这使得老一代使用的内存越来越大,我只是手动点击“执行GC”按钮,似乎这个GC相当有效,回收了很多内存。但是为什么老一代的GC在这么长时间内没有自动发生呢?我们可以看到,在昨天18:00之前,老一代GC工作正常。

您的内存泄漏发生在MongoDB代码中。您看到的大量映射条目很可能是
BasicDBObject
(在转储中排名第6位)的内部,它扩展了
HashMap
。您可以通过重新配置MongoDB组件来解决此问题。

假设在获取jmap时未添加-histo:live选项,这将导致获取带有垃圾+活动对象的报告,并参考手动单击“执行GC”按钮时发生的内存丢失,我怀疑应用程序没有内存泄漏,但从年轻一代到老一代的对象升级率不好。最终老一代将被填满,并将运行完全GC,导致应用程序没有响应

如果我的假设是正确的,我认为您的策略应该是尽量减少将对象升级到老一代,而不是担心如何清除更昂贵的老一代。参考您提到的以下评论,我认为相对于最大分配内存7G,您的应用程序的内存占用量较小(<0.5G)

我所有的数据密集型变量都是在方法中定义的。当方法返回时,这些变量应该被回收,对吗

所以你能做的事情很少

  • 调整应用程序以最小化事务的响应时间,以便在将对象升级到旧版本之前对其进行垃圾收集

  • 增加年轻一代的体型。既然您有大约7GB的可用空间,为什么不先为Young Gen分配大约2-3GB(即-XX:NewSize=2g)。更大的新尺寸将减少PCSAAvenge(年轻收藏)的频率,并降低活动对象的老化率

  • 然后开始调整-XX:MaxTenuringThreshold=n。您可以使用-XX:+PrintTenuringDistribution将gc.log发送给我们。确定幸存者比率的大小-XX:survivoratio=n。请注意,默认情况下-XX:+UseAptiveSizePolicy处于启用状态,这将动态更改幸存者比率的初始大小。或者,您可以跳过调整幸存者比率的步骤,让AdaptiveSizePolicy来执行此任务。但我不是适应性策略的忠实粉丝

  • 除了AdaptiveSizePolicy,您还可以使用-XX:MaxGCPauseMillis=n,以便在清除旧的Gen时向垃圾收集器指示您在应用程序中期望的暂停。这样,收集器将尝试通过不等待太多的工作来实现MaxGCPauseMillis

  • 或者,您可以切换到CMS收集器,该收集器是为处理此类响应时间问题而构建的


我想如果前两步解决了你的问题,那么你可以把剩下的放在一边。你不能通过添加一些额外的东西来破坏一个运行良好的应用程序。重要的是您必须一步一步地调整GC。

很明显,您有一个大型
LinkedHashMap
包含大约400万个字符串。如果我是你,我会专注于弄清楚那张地图是什么,是否需要它,如果不需要,为什么要保留它。(注意,可能有多个
LinkedHashMaps
加起来就是上述内容。这不会改变我的任何建议。)谢谢你提出一个明确的问题。(+1)servlet只实例化一次,所以如果它有一些声明的属性,所有线程都可以使用它。所以,如果您的servlet实现包含一个大型集合,也许您应该检查它是如何增长的,以及它是否可以重置。但在我的servlet中,我没有定义任何静态变量或实例变量。我所有的数据密集型变量都是在方法中定义的。当方法返回时,这些变量应该被回收,对吗?可能比单个大型HashMap更可能是指向HashMap的HashMap指向HashMap。。。或者类似的东西。我想我遇到了一位专家。我的java servlet程序用于接收客户机的MongodDB请求并查询MongodDB,最后将结果(如您所说的DBObject列表)返回给客户机。我所有的变量都是在方法中定义的,而不是在类中定义的,所以,为什么会发生内存泄漏?我的第一个怀疑是缓存,这就是我所说的尝试重新配置MongoDb组件的建议。