解决应用程序类加载器泄漏
应用领域 倾向于:
- 使用应用程序类加载器中的Runnable实现启动新线程。 即使JEE编程模型不支持此功能,客户也经常直接创建新线程或通过使用间接创建它们 计时器 客户必须确保在停止相应的应用程序(或WAR模块)时停止这些线程:
- 可以在停止WAR进行清理时使用javax.servlet.ServletContextListener.contextDestroyed进行通知。
- 使用ThreadLocal的 ( 静态存储一个ThreadLocal)。 ThreadLocal值有效地作为WeakHashMap存储在每个Thread中 。 由于这些值通常包括应用程序对象,因此该应用程序对象引用其Class ,该Class引用其ClassLoader ,该ClassLoader引用包含ThreadLocal的Class ,弱引用永远不会中断,并且会发生泄漏。
鼓励客户避免使用 ThreadLocal ,或者在模块停止时清除对ThreadLocal的引用(请参见上文),或者确保在每次请求后都调用remove() 。
- 向JMX服务器注册JMX MBean或NotificationListener 。 客户必须确保在停止相应的应用程序(或WAR模块)时取消注册。
任意组件
这包括JDBC提供程序,第三方软件和本身想要实现以下目的的应用程序:
- 启动新线程,包括由java.util.Timer构造函数创建的“定时器线程”。 创建线程时 ,将从原始线程复制两条信息:
- 上下文类加载器( getContextClassLoader() )。 当应用程序正在执行时,容器将上下文类加载器设置为模块类加载器,因此新创建的线程将在上下文类加载器存在期间保持其活动状态。 可以通过在启动计时器之前调用setContextClassLoader到非应用程序类加载器来避免这种情况,然后再将其重置。
- 调用线程的AccessControlContext (如AccessController所述 )。 如果线程是由于来自应用程序的API调用而启动的,则应用程序的ProtectionDomain将位于AccessControlContext中 ,并且应用程序类的ProtectionDomain将包括对其ClassLoader的引用。 通过使用doPrivileged创建线程可以避免这种情况。 请注意,必须注意确保使用doPrivileged不允许非特权应用程序创建线程。
例如:
// doPrivileged fixes the AccessControlContext leak, and it is also required // for calls to Thread.get/setContextClassLoader. Timer timer = AccessController.doPrivileged(new PrivilegedAction() {public void run() {Thread thread = Thread.currentThread();ClassLoader savedCL = thread.getContextClassLoader();thread.setContextClassLoader(null);try {// The Timer constructor will create a Thread, which will copy the// context class loader from the current thread, which is now null.return new Timer(true);} finally {thread.setContextClassLoader(savedCL);}} });
- 将数据与当前上下文类加载器关联。 这通常是通过Map <classloader Value> </ classloader完成的 。 此地图必须:
- 具有明确的生命周期API。 在这种情况下,必须调用生命周期API。 如果代码是由客户介绍的,则客户负责添加JMX侦听器。 如果代码是由WAS prereq引入的,则所有者必须使用WAS应用程序侦听器API。 如果代码属于JDK,则运行时团队将承担调用它的责任(例如ResourceBundle.clearCache和Introspector.flushCaches )。
- 成为WeakHashMap以允许对ClassLoader键进行垃圾收集。 请注意,该值不得包含对从该ClassLoader创建的类或对象的非弱引用,否则该条目将永远不会被删除。 WeakHashMap <ClassLoader,WeakReference <Class >>或WeakHashMap <ClassLoader,Tuple>,其中Tuple包含从类实例化的对象的WeakReference <Class>和WeakReference <Object>。 在这两种情况下,Class的保持都很弱,这仍然允许ClassLoader的收集。 在后一种情况下,如果发生GC,将清除对实例化对象的引用,但假定可以廉价地重新实例化它。
这些提示由WAS专家Brett Kail提供
参考:来自JCG合作伙伴的 WebSphere Classloader内存泄漏预防 All Things WebSphere博客上的Rohit Kelapure。
翻译自: https://www.javacodegeeks.com/2012/03/websphere-classloader-memory-leak.html