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

了解Groovy / Grails类加载器泄漏

常子濯
2023-03-14
问题内容

昨天,我将第一个Grails(2.3.6)应用程序部署到开发服务器并开始对其进行监视。我刚得到一个自动监视器,指出CPU已固定在这台计算机上,因此我通过SSH进入了它。我跑去top,发现固定服务器的是我的Java应用程序的PID。我还注意到内存为40%。几秒钟后,CPU停止固定,下降到正常水平,内存下降到〜20%范围。经典大型GC。

在收集时,我进行了堆转储。GC之后,然后我在JVisualVM中打开转储,并看到大部分内存已分配给一个org.codehaus.groovy.runtime.metaclass.MetaMethodIndex.Entry类。总共有将近250,000个实例,消耗了大约25
MB的内存。

我在该课程上进行了搜索,并查看了它非常有用的Javadocs。所以我仍然不知道这堂课是做什么的。

但是,使用谷歌搜索还提出了涉及该类的十几篇相关文章(其中有些是SO问题),以及有关Grails / Groovy应用程序的PermGen /
classloader泄漏。尽管我的应用程序实际上确实使用GC清理了这250K实例,但仍然令人困扰的是它的实例太多,而且GC将CPU固定了5分钟以上。

我的问题:

  • 此类是什么课,Groovy对此做了什么?
  • 有人可以向我解释这个答案吗?为什么会-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled帮助解决这个特定问题?
  • 为什么该类对PermGen特别麻烦?

问题答案:

Groovy是一种动态语言,每个方法调用都是动态调度的。以优化Groovy中创建一个MetaClass为每个java.lang.ClassMetaClassRegistry。这些MetaClass实例是按需创建的,并使用弱引用进行存储。

之所以看到很多,org.codehaus.groovy.runtime.metaclass.MetaMethodIndex.Entry是因为Groovy将类和方法的映射存储在内存中,以便可以在运行时快速调度它们。取决于应用程序的大小,这可能是因为您已经发现了数千个类,因为每个类可以具有数十个有时数百个方法。

但是,在Groovy和Grails中没有“内存泄漏”,您看到的是正常行为。您的应用程序内存不足,可能是因为尚未为其分配足够的内存,从而导致MetaClass实例被垃圾回收。现在假设您有一个循环:

for(str in strings) {
   println str.toUpperCase()
}

在这种情况下,我们正在String类上调用一个方法。如果内存不足,则将发生以下情况:对于循环的每次迭代,MetaClass将对其进行垃圾回收,然后再次为下一次迭代重新创建。如您所见,这会大大降低应用程序的运行速度,并导致CPU被固定。此状态通常称为“元类搅动”,是您的应用程序堆内存不足的标志。

如果Groovy中 没有 垃圾收集这些MetaClass的情况下,那么是的,这将意味着有在Groovy内存泄漏,但事实证明 这是
垃圾收集这些类是一个迹象,一切都很好,只是,你还没有分配到足够的事实首先堆内存。这并不是说在应用程序的另一部分中可能存在内存泄漏,这正在耗尽所有可用的内存,并且不足以使Groovy正常运行。

至于您提到的其他答案, 除非 您在运行时动态解析类, 否则
添加类卸载和PermGen调整实际上不会解决内存问题。JVM使用PermGen空间存储动态创建的类。Groovy允许您在运行时使用GroovyClassLoader.parseClass或编译类GroovyShell.evaluate。如果您要连续解析类,那么可以添加类卸载标志会有所帮助。

但是,典型的Grails应用程序 不会 在运行时动态编译类,因此调整PermGen和类卸载设置实际上并不会实现任何目的。

您应该使用-Xmx标志验证是否分配了足够的堆内存,如果没有分配更多的堆内存,则应使用-Xmx标志。



 类似资料:
  • 我在Tomcat 8中热重新部署简单的Grails应用程序时遇到问题。 我的设置如下: Grails 2.5.1全新的应用程序,刚刚使用创建 Tomcat 8.0.28(64位Linux二进制版本) Java1.80_65-b17 HotSpot服务器VM Tomcat也是一个全新的安装,只修改了两件事(因为我想在生产中使用它们): 服务器xml

  • 问题内容: 我有一个Grails应用程序,该应用程序完成了相当不错的域对象创建和销毁工作,而且它似乎以非常非常快的速度耗尽了PermGen空间。我已经进行了通常的调整(将PermGen调整为256M,启用了类GC,等等),但是没有骰子。 有人愿意推荐一些(可能是免费或非常便宜的)工具来解决Groovy和/或Java中的这种内存消耗问题吗?还是您用来解决JVM内存问题的某些技术? 编辑:这是在生产模

  • 问题内容: 我在Glassfish上部署了一个应用程序。随着时间的流逝,加载的类的数量攀升至数百万,而我的表现似乎正在上升。 为了帮助排除故障,我在jvm参数中添加了以下内容。-XX:+ PrintGCDetails -XX:+ TraceClassUnloading -XX:+ TraceClassLoading 现在,当观看输出时,我看到相同的类一遍又一遍地加载。基本上,每次调用Web服务并且

  • 我正试图用PDFBox和Groovy来搞乱一下。我试图使用PDType1Font类的getStringWidth()方法计算字符串的宽度。 我的问题是,每次编译和运行代码时,都会出现这样一个错误: 代码如下: 为了清晰起见,我删除了代码中所有不相关的部分。 问题出在哪里? 更新:我在IntelliJ中搜索了一下如何将外部jar添加到我的类路径,发现我需要转到项目结构- 我试着这样做: 但我仍然收到

  • 由于我升级到android studio 3.0.1,我无法继续使用我的应用程序。Gradle引发以下错误:Gradle同步问题 错误:无法加载类“groovy.lang.GroovyObject”。此意外错误的可能原因包括: 有什么建议吗?非常感谢你。

  • 我尝试在一个java swing应用程序的缓存实例附近设置两个Oracle Coherence。这里可以找到解决方案。我的案子有点复杂,这就是游戏开始的地方。 在我的情况下,有一个帐户服务。它可以有两个endpoint:SIT和UAT。为了创建两个这样的服务,我需要加载Coherence的两个“实例”,以便用系统变量(tangosol.Coherence.cacheConfig)覆盖endpoin