java gc根_java – 即使没有GC根,Classloader也不会被垃圾收集

我们有一个在Glassfish V2.1.1下运行的复杂应用程序.为了能够动态加载我们的代码,我们实现了一个CustomClassloader,它能够重新定义类.

行为非常简单:当动态加载的类发生更改时,CustomClassloader的当前实例将被“删除”,并创建一个新实例以重新定义所需的类.

这很好用,除了在重新加载相同的类几次之后(因此每次创建一个新的CustomClassloader),我们得到一个PermGen空间错误,因为CustomClassloader的其他实例不是垃圾收集的. (这个类应该只有一个实例)

我尝试了不同的方法来追踪泄漏的位置:

> visualvm =>我进行堆转储并提取CustomClassloader的所有实例.我可以看到他们都没有最终确定.当我检查最近的GC根时,visualvm告诉我没有(除了最后一个实例,因为它是’真实的’使用过的).

> jmap/jhat =>它给了我几乎相同的结果:我看到CustomClassloader的所有实例,然后当我点击链接以查看其中一个的引用位置时,我得到一个空白页面意味着没有…

> Eclipse Memory Analyzer Tool =>当我运行以下OQL查询时,我得到一个奇怪的结果:

选择c FROM INSTANCEOF my.package.CustomClassloader c

只有一个结果,表明只有一个实例显然不正确.

我还检查了这个link,并在创建一个新的CustomClassloader时实现了一些资源释放,但没有任何变化:PermGen内存仍在增加.

所以我可能错过了一些东西,点(1-2)和(3)之间的区别显示了我不理解的东西.我在哪里可以了解什么是错的?

由于我所遵循的所有教程都显示了如何使用“搜索最近的GC根”功能搜索泄漏的引用(在我的情况下没有),我不知道如何跟踪错误.

编辑1:我上传了一个堆转储here的示例.可以使用以下查询在visualvm中选择未卸载的ClassLoader:select s from saierp.core.framework.system.SAITaskClassLoader s

可以看到有4个实例,并且应该已经收集了第3个实例,因为没有GC根…必须有某个引用,但我不知道如何搜索它.任何提示都欢迎:)

编辑2:经过一些更深入的测试,我看到一个非常奇怪的模式.泄漏似乎取决于OpenJPA正在加载的数据:如果没有加载新数据,那么类加载器可以是GCed,否则不是.下面是我创建一个新的SAITaskClassLoader以“清除”旧代码时使用的代码:

PCRegistry.deRegister(cl);

LogFactory.release(cl);

ResourceBundle.clearCache(cl);

Introspector.flushCaches();

=模式1(类加载器已GCed):=

>新的SAITaskClassLoader

>加载数据D1,D2,…,Dn

>新的SAITaskClassLoader

>加载数据D1,Dn

> ……

=模式2(类加载器未GCed):=

>新的SAITaskClassLoader

>加载数据D1,D3

>新的SAITaskClassLoader

>加载数据D3,D4,D5

>新的SAITaskClassLoader

>加载数据D5,D6,D7

> ……

在所有情况下,已清除的SAITaskClassLoader都没有GC根.我们正在使用OpenJPA 1.2.1.

谢谢&最好的祝福

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值