IAm*_*aja 10 java grails groovy memory-leaks classloader
昨天我将我的第一个Grails(2.3.6)应用程序部署到开发服务器并开始监控它.我刚刚得到一个自动监视器,说明CPU被固定在这台机器上,所以我连接到它.我跑了top
,发现是我的Java应用程序的PID固定服务器.我也注意到内存是40%.几秒钟后,CPU停止固定,降至正常水平,内存恢复到~20%范围内.经典主要GC.
在收集的同时,我做了堆转储.在GC之后,我在JVisualVM中打开了转储,并看到大部分内存都是为一个org.codehaus.groovy.runtime.metaclass.MetaMethodIndex.Entry
类分配的.总共有近250,000个这样的实例,占用了大约25 MB的内存.
我用Google搜索了这个课程并看了一下它是非常有帮助的Javadocs.所以我仍然不知道这门课做了什么.
但谷歌搜索它也带来了大约十几篇涉及这个类的相关文章(其中一些是SO问题)和Grails/Groovy应用程序的PermGen/classloader泄漏.虽然看起来我的应用程序确实用GC清理了这些250K实例,但仍然令人不安的是它有如此多的实例,并且GC将CPU固定超过5分钟.
我的问题:
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
帮助这个特殊问题?Gra*_*her 13
Groovy是一种动态语言,每个方法调用都是动态调度的.以优化Groovy中创建一个MetaClass
为每个java.lang.Class
中MetaClassRegistry
.这些MetaClass
实例是按需创建的,并使用弱引用进行存储.
你看到很多的原因org.codehaus.groovy.runtime.metaclass.MetaMethodIndex.Entry
是因为Groovy在内存中存储了类和方法的映射,以便运行时可以快速分派它们.根据应用程序的大小,这可能是因为您已经发现了数千个类,因为每个类可以有几十个有时数百个方法.
但是,Groovy和Grails中没有"内存泄漏",你看到的是正常行为.您的应用程序内存不足,可能是因为它没有分配足够的内存,这反过来会导致MetaClass
实例被垃圾回收.现在说比如你有一个循环:
for(str in strings) {
println str.toUpperCase()
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们在String
类上调用一个方法.如果内存不足,将会发生的事情是,对于循环的每次迭代,MetaClass
将进行垃圾收集,然后再次重新创建以用于下一次迭代.这可能会大大减慢应用程序的速度,并导致CPU被固定,如您所见.此状态通常称为"元类流失",是应用程序在堆内存上运行不足的标志.
如果Groovy 不是垃圾收集这些MetaClass实例,那么是的,这意味着Groovy中存在内存泄漏,但事实上它是垃圾收集这些类,这表明一切都很好,除了你没有足够的分配堆内存首先.这并不是说应用程序的另一部分可能存在内存泄漏,这会占用所有可用内存,并且不足以让Groovy正常运行.
至于你提到的另一个答案,添加类卸载和PermGen调整实际上不会做任何事情来解决你的内存问题,除非你在运行时动态解析类.JVM使用PermGen空间来存储动态创建的类.Groovy允许您使用GroovyClassLoader.parseClass
或在运行时编译类GroovyShell.evaluate
.如果你不断解析类,那么添加类卸载标志可以提供帮助.另见这篇文章:
但是,典型的Grails应用程序不会在运行时动态编译类,因此调整PermGen和类卸载设置实际上不会实现任何功能.
您应该使用-Xmx标志验证是否已分配了足够的堆内存,如果没有分配更多内存.
归档时间: |
|
查看次数: |
5524 次 |
最近记录: |