有一个应用平台是基于eclipse rcp技术开发的。此平台支持应用逻辑类动态加载。此平台采用的自定义类加载器来加载具体应用业务逻辑处理类。平台定时扫描已经加载过的类是否改变过。如果有类的已经改变了则创建新的类加载器,平台通过新的类加载器加载应用逻辑处理类。
有一天,使用MAT工具分析java的heapdump。发现有很多自定义类加载器存在。而且出现多份同名应用业务逻辑处理类的Class。
这明显存在内存泄露的问题。
通过MAT工具的多种功能反复研究,终于找到了一个意料不到内存泄露原因。元凶竟然是eclipse内部AdapterManager。AdapterManager缓存了应用业务逻辑处理类的Class对象。
AdapterManager为什么会缓存应用业务处理逻辑类呢?
此平台定义一个应用业务逻辑处理类的抽象父类。此父类实现了接口org.eclipse.core.runtime.IAdaptable。此接口只有一个方法:
此抽象父类实现IAdaptable的方法如下:
这样处理可以给具体应用业务处理逻辑类调用平台的公共服务接口带来方便。调用者不需要知道接口的实现类是谁,此接口的实现是在哪里。
调用者只需要类似如下调用就可使用一些公共服务:
- IHttpCommunication httpComm=(IHttpCommunication)this.getAdapter(IHttpCommunication.class);
- IPrintService printService=(IPrintService)this.getAdapter(IPrintService.class);
AdapterManager为什么要缓存一些Class呢?
AdapterManager的loadAapter会调用一个方法:
缓存的目的就是为了方便查找IAdapterFactory。
找到了问题的根源,解决办法就呼之欲出了。在创建新的自定义类加载器时,主动调用AdapterManager的flushLookup就可以了。