解決應用程序類加載器泄漏
應用領域 傾向于:
- 使用應用程序類加載器中的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