Memory leaks 未垃圾收集自定义类加载器

Memory leaks 未垃圾收集自定义类加载器,memory-leaks,garbage-collection,classloader,openjpa,glassfish-2.x,Memory Leaks,Garbage Collection,Classloader,Openjpa,Glassfish 2.x,为了解决这个问题,我建立了一个非常小的模型来复制它的一部分。这是一个使用Glassfish v2.1.1和OpenJpa-1.2.2的NetBeans项目 在全球范围内,我们的目标是能够动态地重新加载一些称为“任务”的业务代码,而无需重新进行完整的部署(例如通过asadmin)。在这个项目中有两个任务:PersonTask和AddressTask,它们只是访问一些数据并打印出来 为了做到这一点,我实现了一个自定义类加载器,它读取类文件的二进制文件,并通过defineClass方法注入它。基本上,

为了解决这个问题,我建立了一个非常小的模型来复制它的一部分。这是一个使用Glassfish v2.1.1和OpenJpa-1.2.2的NetBeans项目

在全球范围内,我们的目标是能够动态地重新加载一些称为“任务”的业务代码,而无需重新进行完整的部署(例如通过asadmin)。在这个项目中有两个任务:PersonTask和AddressTask,它们只是访问一些数据并打印出来

为了做到这一点,我实现了一个自定义类加载器,它读取类文件的二进制文件,并通过defineClass方法注入它。基本上,这个CustomClassLoader是一个单例,实现方式如下:

公共类CustomClassLoader扩展了ClassLoader{ 私有静态CustomClassLoader实例; 私有静态int staticId=0; private int id;//用于在VisualVM中调试 私有长线程ID;//用于在VisualVM中调试 私有CustomClassLoader ClassLoader父级{ 超级家长; threadId=Thread.currentThread.getId; id=staticId; ++静态ID; } 私有静态CustomClassLoader getNewInstance{ 如果实例!=null{ CustomClassLoader ccl=实例; 实例=null; PCRegistry.deRegisterccl//https://issues.apache.org/jira/browse/GERONIMO-3326 ResourceBundle.ClearCacheCl;//使用Eclipse内存分析器工具时在其中找到一些引用 内省者。冲洗缓存//http://java.jiderhamn.se/category/classloader-leaks/ System.runFinalization; System.gc; } ClassLoader父级=Thread.currentThread.getContextClassLoader; 实例=新CustomClassLoaderparent; 返回实例; } //... } //该类与普通类一样包含在EAR中 公共抽象类抽象任务{ 受保护的数据库;/*EntityManager的包装,在创建实例时填充*/ 公共抽象void processInteger id; } //这个由CustomClassLoader动态加载 公共类PersonTask扩展了抽象任务{ @凌驾 public-void-processInteger-id{ //暂时让它空着 } } 在我的EJB facade EntryPointBean中,我只需查找该类,创建一个新的实例,并对其调用流程方法。项目中的代码略有不同,但想法完全相同:

CustomClassLoader=CustomClassLoader.getNewInstance; clazz类=loader.loadClassch.leak.tasks.PersonTask; 对象实例=clazz.newInstance; AbstractTask=AbstractTaskinstance; /*将新数据库实例注入到任务中*/ 任务。过程。。。; 直到现在,一切都很好。如果通过ch.leak.test.test多次运行此代码,则在完成堆分析时,CustomClassLoader只有一个实例,这意味着已成功收集以前的实例

现在,下面是触发泄漏的管线:

公共类PersonTask扩展了抽象任务{ @凌驾 public-void-processInteger-id{ Person p=database.getentity从Person p中选择p,其中p.personpk.idpk=?1,新Longid; //... } } 这种对数据库的简单访问有一个奇怪的结果:第一次运行代码时,即使没有任何GC根,也不会对正在使用的CustomClassLoader进行垃圾收集。但是,所有进一步创建的CustomClassLoader都不会泄漏

正如我们在下面使用VisualVM完成的转储中所看到的,实例id为0的CustomClassLoader从未被垃圾收集。。。

最后,在探索堆转储时,我还看到了另一件事:我的实体在PermGen中声明了两次,其中一半没有实例,也没有GC根,但它们没有链接到CustomClassLoader。

似乎OpenJPA与这些漏洞有关。。。但我不知道在哪里可以找到更多关于我做错了什么的信息。我还将堆转储直接放在项目的zip中。 有人有主意吗

谢谢

我在这里创建了一个bug报告:它似乎真的与OpenJPA有关,动态查询也可以看到另一个bug:因为EclipseLink根本没有这个问题。