2013-05-06 42 views
4

我有一個基於SpringRoo的應用程序在生產環境中運行,這是一些熱重新部署後導致嚴重的permgen內存泄漏。Permgen內存泄漏與熱重新部署和Oracle數據庫

爲了「查找並修復」泄漏並減少分析過程中的變量,我使用roo創建了一個簡單的,簡化的應用程序,並且我獲得了相同的行爲。 該項目(使用Spring Roo(1.2.3.RELEASE)創建)只是將名爲'Person'的實體與名爲'name'的字符串字段保持一致。

我將戰爭部署在Tomcat 7.0.39上,使用Oracle 11.2.0.2作爲數據庫。 每次重新部署後,我得到了catalina.out的

INFO: Undeploying context [/ojdbc-0.1.0.BUILD-SNAPSHOT] 
mag 06, 2013 10:50:43 AM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc 
SEVERE: The web application [/ojdbc-0.1.0.BUILD-SNAPSHOT] registered the JDBC driver  [oracle.jdbc.OracleDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered. 

此消息兩個熱重新部署,我得到一個PermGen的錯誤後:

mag 06, 2013 10:51:08 AM org.apache.catalina.startup.HostConfig deployWAR 
INFO: Deploying web application archive /Applications/apache-tomcat-7.0.39/webapps/ojdbc- 0.1.0.BUILD-SNAPSHOT.war 
Exception in thread "ContainerBackgroundProcessor[StandardEngine[Catalina]]" 
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "ContainerBackgroundProcessor[StandardEngine[Catalina]]" 
Exception in thread "RMI TCP Connection(idle)" mag 06, 2013 10:51:17 AM ServerCommunicatorAdmin reqIncoming 
WARNING: The server has decided to close this client connection. 
java.lang.OutOfMemoryError: PermGen space 
Exception in thread "RMI TCP Connection(idle)" java.lang.OutOfMemoryError: PermGen space 

我試圖分析這種與VisualVm/EclipseMemory分析器,這是我到目前爲止。

VisualVM screnshot with PermGen behaviour

GC Roots obtained from dominator tree analysis

事實是,我不與其它數據庫(例如PostgreSQL的,高超音速)觀察此行爲。是否有與Oracle相關的東西導致泄漏?

Here是一個包含roo腳本生成器和an.hprof轉儲文件的zip壓縮文件。

回答

0

嘗試將Oracle JDBC驅動程序移動到Tomcat的lib目錄中,而不是位於應用程序的lib文件夾內。它看起來像OracleDiagnosabilityMBean正在掌握Catalina。

編輯:既然你不擁有控制權的Tomcat,儘量裹在甲骨文類越來越加載像這樣(除了更換AppContext爲Oracle INIT):

http://cdivilly.wordpress.com/2012/04/23/permgen-memory-leak/

//somewhere in application startup, e.g. the ServletContextListener 
try { 
final ClassLoader active = Thread.currentThread().getContextClassLoader(); 
try { 
    //Find the root classloader 
    ClassLoader root = active; 
    while (root.getParent() != null) { 
    root = root.getParent(); 
    } 
    //Temporarily make the root class loader the active class loader 
    Thread.currentThread().setContextClassLoader(root); 
    //Force the AppContext singleton to be created and initialized 
    sun.awt.AppContext.getAppContext(); 
} finally { 
//restore the class loader 
Thread.currentThread().setContextClassLoader(active); 
} 
} catch (Throwable t) { 
    //Carry on if we get an error 
    LOG.warning("Failed to address PermGen leak"); 
} 
+0

好吧,你的答案感謝,不幸的是,應用服務器是不是我的管理下.. 。現在我已經在一個臨時的tomcat下部署了應用程序,我可以隨時重新啓動。 這不是一個解決方案,當然......但它是我迄今爲止唯一的解決方案... – paoloyx 2013-07-01 12:28:48

+0

編輯原始答案並附加內容 – Ryan 2013-07-01 13:08:44

+0

好的,非常感謝你,我會試一試。 我會讓你知道結果。 – paoloyx 2013-07-03 08:24:36

0

有一個內部的Oracle錯誤報告

Oracle Support Bug 18707079 (JDBC THIN DRIVER LEAKS THREADS AND REFERENCES ON WEBAPP SHUTDOWN):https://support.oracle.com/epmos/faces/BugDisplay?id=18707079

其德抄寫你的問題:

When the webapp is shutdown, customer experience the following problems: 
1) The OracleDiagnosabilityMBean is not de-registered 
2) OracleTimeoutPollingThread does not stop 
3) The following thread does not stop: 
oracle.jdbc.driver.BlockSource.ThreadedCachingBlockSource.BlockReleaser 

它被設置爲Fixed in Product Version 12.2。希望它很快就會發布!

0

試試這個:

在網頁XML註冊一個的ServletContextListener

<listener> 
    <listener-class>my.package.MyShutdownServletContextListener</listener-class> 
</listener> 

來源:

public class MyShutdownServletContextListener implements ServletContextListener { 
@Override 
public void contextInitialized(ServletContextEvent event) { 
    final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 
    try { 
     Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader()); 
     java.sql.DriverManager.getDrivers(); 
     Class.forName("oracle.jdbc.driver.OracleTimeoutThreadPerVM"); 
    } catch (ClassNotFoundException e) { 
     /* noop */ 
    } finally { 
     Thread.currentThread().setContextClassLoader(contextClassLoader); 
    } 
} 
@Override 
public void contextDestroyed(ServletContextEvent event) {} 
}