`
wx1569020408
  • 浏览: 26893 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Groovy动态加载类踩中的那些坑...

 
阅读更多

告警显示tp-audit的多个应用间隔性发生GC:ConcurrentMarkSweepCount(OldGC)引起了我们的注意。

现象:

观看我们公司(点评)cat监控平台

这是同一个小时内的图像,由图可知oldgc次数一分钟保持在6次左右,然而老年代内存依然坚挺使用高达900多M,没有下降趋势。

正常应用发生oldgc,老年代内存理论上应该被释放掉绝大部分。

 

由此我们可以判断出程序肯定有某处发生了内存泄漏。

 

用了ha456.jar、MAT、VisualVM、JProfiler等工具和请教各路大神分析得知

AppClassLoader里主要ConcurrentHashMap占用内存最大,而ConcurrentHashMap里主要存放的几乎都是Groovy动态生成的类名

这个ConcurrentHashMap存放了近600万个Entry

 

原因:

AppClassLoader是java内置类加载器,用来加载用户应用程序的类。里面有一个parallelLockMap,

主要用来存储类锁,避免JVM加载同名的类,和提高类加载的并发度。

 

GroovyClassLoader如果加载的是无类名的Script,最终会生成一个随机的类名,每次都不一样。

导致parallelLockMap不断膨胀,幸运的是parallelLockMap只存储一个name和Object,并不会占用过多空间。

所以现象就是上线半个多月都没有问题,一个月后才会内存吃紧。8G的LVS甚至几个月都不会有问题。

 

这应该是一个JDK的BUG,只要加载过多的不同类,parallelLockMap就会不断的膨胀,导致memory leak

最终机器就会宕机。这个这个BUG早已经提给官方,但是JDK7、JDK8都未修复,而且明确指出不修复。

 

结论:

理论上是不合理的,因为这个Map只进不出。既然官方指出不修复,那我们只能规范使用流程了。

无论是Groovy还是通过别的方式动态加载类,尽量使用固定类名。如果类名是随机的,就要控制加载数量了。

如果你是4G的LVS,可以放心的创建500万个不同名的类。毛估500万个不同类名,占用大约800M内存。

如果程序仅加载变更后的类,相信500万次变更是肯定够用的。

如果还不够,那只能通过加内存来解决了。

 

使用Groovy动态加载类就算跳过了自带的无法卸载的类的坑,还是会踩进JDK自带的坑。

此次案例详细bug记录请预览https://issues.apache.org/jira/browse/GROOVY-6655

 

与此次案例无关的BUG预警:

Groovy推荐版本2.3.7,新版本有无法卸载类的坑,很容易导致OOM:PermGen space。

详细bug记录请预览https://issues.apache.org/jira/browse/GROOVY-7913

 

JDK8内存模型更新,默认已经没有PermGen了,也就是说不会发生OOM:PermGen space了。

但是使用的是LVS自带的内存,所以最好还是指定这个参数-XX:MaxMetaspaceSize=128m控制下大小

不然Groovy也会饰无忌惮的吃光LVS内存。

 

Groovy动态加载类使用方式推荐

private static final GroovyClassLoader classLoader = new GroovyClassLoader();

public static Script loadScript(String rule) {

    return loadScript(rule, new Binding());

}

public static Script loadScript(String rule, Binding binding) {

    Script script = null;

    if (StringUtils.isEmpty(rule)) {

        return null;

    }

    try {

        Class ruleClazz = classLoader.parseClass(rule);

        if (ruleClazz != null) {

            log.info("load rule:" + rule + " success!");

            return InvokerHelper.createScript(ruleClazz, binding);

        }

    catch (Exception e) {

        log.error(e.getMessage(), e);

    finally {

        classLoader.clearCache();

    }

    return script;

}

因为

GroovyClassLoader是static的,所以想卸载无引用的Class,要执行classLoader.clearCache();

如果GroovyClassLoader每次都是new出来的,可以忽略执行classLoader.clearCache();

转载于:https://my.oschina.net/chenxiaojie/blog/835934

分享到:
评论

相关推荐

    Java调用Groovy,实时动态加载数据库groovy脚本

    2. 创建GroovyClassLoader:使用这个类加载器可以动态加载和执行Groovy脚本。它继承自Java的ClassLoader,能解析Groovy源码并生成字节码。 3. 加载并执行Groovy脚本:通过GroovyClassLoader的`parseClass()`方法...

    groovy-all-1.8.1.jar.zip

    由于其与Java的兼容性,Groovy也被广泛应用于混合Java和Groovy的项目中,提供了一种在现有Java项目中引入动态性的途径。 总之,"groovy-all-1.8.1.jar.zip"是Groovy 1.8.1版本的集合库,包含了执行Groovy代码所需的...

    groovy-all-2.4.15.jar.zip

    groovy-all-2.4.15.jar文件,MAC使用时需存放在/Users/用户名/.gradle/caches/jars-3/某一缓存目录下,找不到就都看一下,我遇到的问题是缓存目录中下载的是2.4.17版本,应该跟gradle版本升级有关

    Groovy.in.Action.2nd.Edition.pdf

    在前言中,我们看到James Gosling,Java的创始人,对此书给予高度评价,这也反映了Groovy在动态语言特性以及在敏捷开发方面的表现。 本书详细介绍了Groovy语言的多个方面,包括但不限于以下几个核心知识点: 1. ...

    groovy programming(2006.12).pdf

    由于Groovy与Java的高度兼容性,本书特别强调了如何在Java项目中使用Groovy脚本或Groovy类。这包括如何在Java代码中调用Groovy脚本,以及如何在Groovy中调用Java类库。这种集成能力使得Groovy可以作为Java项目的脚本...

    groovy-all-2.4.5-API文档-中英对照版.zip

    赠送jar包:groovy-all-2.4.5.jar; 赠送原API文档:groovy-all-2.4.5-javadoc.jar; 赠送源代码:groovy-all-2.4.5-sources.jar; 赠送Maven依赖信息文件:groovy-all-2.4.5.pom; 包含翻译后的API文档:groovy-all...

    Groovy.for.Domain.Specific.Languages.pdf

    Groovy的灵活性允许开发者自由地定制语法,甚至可以通过注解或元类来定义新的语法元素。 #### 3. 实现和测试DSL 利用Groovy的特性实现DSL的解析和执行逻辑。这通常涉及到编写解释器或编译器,将DSL代码转换成可执行...

    Groovy入门教程[参照].pdf

    Groovy 是一种基于 Java 语言的脚本语言,运行在 JVM 中,语法与 Java 相似,但抛弃了 Java 的一些烦琐的语法规则,提供了更加简洁和灵活的编程体验。 Groovy 的特点 1. 简洁的语法:Groovy 语法简洁,减少了代码...

    apache-groovy-sdk-2.5.15.zip

    Apache Groovy SDK 2.5.15 是一个强大的、动态的编程语言,与Java平台紧密集成,提供了简洁的语法和强大的元编程能力。这款SDK(Software Development Kit)包含了Groovy语言的运行环境和开发工具,是开发人员进行...

    groovy-loader:在文件目录中动态加载Groovy脚本

    动态加载指定目录下的groovy脚本,并将其注册为groovy bean,放置于ApplicationContext容器中,并使用命名空间进行分类区分(一个namespace对应于一个ApplicationContext)。同时能够动态感知到groovy脚本的新增、修改...

    groovy-3.0.9-API文档-中文版.zip

    赠送jar包:groovy-3.0.9.jar; 赠送原API文档:groovy-3.0.9-javadoc.jar; 赠送源代码:groovy-3.0.9-sources.jar; 赠送Maven依赖信息文件:groovy-3.0.9.pom; 包含翻译后的API文档:groovy-3.0.9-javadoc-API...

    groovy-all-2.4.12.jar

    最近的groovy-all-2.4.12.jar包供使用,解决as编译时报错问题

    Packtpub.Groovy.for.Domain.Specific.Languages.Jun.2010.rar

    《Packtpub.Groovy.for.Domain.Specific.Languages.Jun.2010》这本书主要聚焦于Groovy语言在领域特定语言(DSLs)中的应用,这是2010年6月出版的一份专业资源。Groovy是一种动态、灵活的编程语言,它为Java平台带来...

    org.codehaus.groovy-2.9.0.xx-201407142235-e44-RELEASE-updatesite.zip

    描述中的 "groovy eclipse plugin 2.9.0" 确认了这是一个用于Eclipse集成开发环境(IDE)的Groovy语言支持插件,版本同样是2.9.0。这意味着开发者可以使用Eclipse IDE来编写、调试和管理Groovy代码,享受Eclipse提供...

    Groovy-3.0.jar

    Groovy jar包 3.0.

    groovy和Java相互调用1

    2. **方法2:反射动态调用** - 使用Java的反射机制,可以在运行时动态加载和执行Groovy类。这种方法的优点是Groovy脚本的修改不需要重新编译整个项目,因为Java代码可以通过反射动态地找到并调用Groovy方法。这里,...

    groovy-all-2.4.15.jar

    org.gradle.api.resources.ResourceException: Could not get resource '...下载groovy-all-2.4.15.jar后,放入对应的 android-studio/gradle/gradle-5.*/lib/目录。 重启 Android Studio 及可使用。

Global site tag (gtag.js) - Google Analytics