我们的 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 进入“内存不足”状态(一直持续),我对其进行了堆转储并在其上运行 Eclipse 内存分析器。
结果很有趣。大约 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 .它远不是一款完美的软件。
最佳答案
Any explanation as to why the VM is having so many unreachable objects, and is uncapable of collecting them at all?
(基于我们在评论中的交流)听起来这不是传统的内存泄漏,而是一些逻辑不断向新对象发送垃圾邮件,使得 GC 难以跟上当前架构。
罪魁祸首可能是某些 API 请求被多次发出,或者被“卡”在某种错误状态,例如我描述的无限分页场景。这两种情况都归结为数百万个响应 gson 对象(指向 Strings(指向 char[]s))被实例化,然后符合 GC 条件.
正如我所说,您应该尝试隔离问题请求,然后进行调试并进行测量以确定这是您的应用程序或其库之一的错误或可伸缩性问题。
关于Java 堆被无法访问的对象淹没,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14370738/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信