2013-05-06 1 views
4

프로덕션 환경에서 실행중인 SpringRoo 기반 응용 프로그램이 있습니다. 이로 인해 일부 재배포 후에 심각한 permgen 메모리 누수가 발생합니다.핫 재배포 및 Oracle 데이터베이스를 사용한 Permgen 메모리 누출

누수를 찾아서 수정하고 분석하는 동안 변수를 줄이기 위해 roo를 사용하여 간단하고 능률적 인 응용 프로그램을 만들었고 동일한 동작을 얻었습니다. 프로젝트 (Spring Roo (1.2.3.RELEASE)로 생성)는 'name'이라는 문자열 필드가있는 'Person'이라는 엔티티를 유지합니다.

Oracle 11.2.0.2를 데이터베이스로 사용하여 Tomcat 7.0.39에 전쟁을 전개합니다. 나는이 분석을 시도한

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 

: 마다 다시 배포 한 후, 나는 핫 다시 배포, 나는 permgen 오류 얻을이 후 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. 

에서이 메시지가 VisualVm/EclipseMemory Analyzer와 함께, 지금까지 내가 얻은 것입니다.

VisualVM screnshot with PermGen behaviour

GC Roots obtained from dominator tree analysis

사실

내가 (예 PostgreSQL을 또는 극 초음속을위한) 다른 데이터베이스로이 동작을 관찰하지 않는다는 것입니다. 누출의 원인이되는 Oracle과 관련된 것이 있습니까?

Here은 roo 스크립트 생성기가 포함 된 zip 아카이브이며, .hprof 덤프 파일을 복원합니다.

답변

0

Oracle JDBC 드라이버를 응용 프로그램의 lib 폴더 안에 있지 않고 Tomcat의 lib 디렉토리로 이동해보십시오. OracleDiagnosabilityMBean이 Catalina를 처리하고있는 것 같습니다.

편집 : 톰캣을 제어 할 수 없기 때문에, (오라클 초기화에 대한 AppContext 교체 제외) 오라클 클래스과 같이로드지고 위치를 포장하려고 :

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

좋아, 감사, 불행하게도 응용 프로그램 서버 내 관리하에 있지 .. .지금은 내가 원할 때마다 다시 시작할 수있는 임시 바람둥이 아래에 응용 프로그램을 배포했습니다. 이것은 해결책이 아닙니다 ... 물론 지금까지 가지고있는 유일한 해결책입니다 ... – paoloyx

+0

추가 내용이 편집 된 원래 응답 – Ryan

+0

감사합니다. 정말 고마워요. 시도해 보겠습니다. 결과에 대해 알려 드리겠습니다. – paoloyx

0

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의

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

소스를 ServletContextListener를 등록하여 답변

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) {} 
}