최근에 웹 응용 프로그램 에서이 오류가 발생했습니다.
java.lang.OutOfMemoryError : PermGen 공간
Tomcat 6 및 JDK 1.6에서 실행되는 일반적인 Hibernate / JPA + IceFaces / JSF 응용 프로그램입니다. 분명히 응용 프로그램을 몇 번 재배치 한 후에 발생할 수 있습니다.
그것을 일으키는 원인과 그것을 피하기 위해 무엇을 할 수 있습니까? 문제를 어떻게 해결합니까?
최근에 웹 응용 프로그램 에서이 오류가 발생했습니다.
java.lang.OutOfMemoryError : PermGen 공간
Tomcat 6 및 JDK 1.6에서 실행되는 일반적인 Hibernate / JPA + IceFaces / JSF 응용 프로그램입니다. 분명히 응용 프로그램을 몇 번 재배치 한 후에 발생할 수 있습니다.
그것을 일으키는 원인과 그것을 피하기 위해 무엇을 할 수 있습니까? 문제를 어떻게 해결합니까?
답변:
해결책은 Tomcat이 시작될 때 이러한 플래그를 JVM 명령 행에 추가하는 것입니다.
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
Tomcat 서비스를 종료 한 다음 Tomcat / bin 디렉토리로 이동하여 tomcat6w.exe를 실행하면됩니다. "Java"탭에서 "Java 옵션"상자에 인수를 추가하십시오. "확인"을 클릭 한 다음 서비스를 다시 시작하십시오.
오류가 발생 하면 지정된 서비스가 설치된 서비스로 존재하지 않습니다 .
tomcat6w //ES//servicename
여기서 servicename 은 services.msc에 표시된 서버 이름입니다.
출처 : Eric의 Agile Answers 에 대한 orx의 의견 .
보다 시도하는 -XX:MaxPermSize=128M
것이 좋습니다 -XX:MaxPermGen=128M
.
이 메모리 풀의 정확한 사용법을 알 수는 없지만 JVM에로드 된 클래스 수와 관련이 있습니다. (톰캣에 클래스 언로드를 활성화하면 문제를 해결할 수 있습니다.) 응용 프로그램이 실행시 클래스를 생성하고 컴파일하는 경우 기본보다 큰 메모리 풀이 필요할 가능성이 큽니다.
여러 배포 후 발생하는 앱 서버 PermGen 오류는 컨테이너가 이전 앱의 클래스 로더에 보유한 참조에 의해 발생합니다. 예를 들어, 사용자 정의 로그 레벨 클래스를 사용하면 앱 서버의 클래스 로더가 참조를 보유하게됩니다. jmap 및 jhat과 같은 최신 (JDK6 +) JVM 분석 도구를 사용하여 앱에서 어떤 클래스가 계속 유지되는지 확인하고 사용을 재 설계 또는 제거하여 이러한 클래스 간 로더 누수를 감지 할 수 있습니다. 일반적인 용의자는 데이터베이스, 로거 및 기타 기본 프레임 워크 수준 라이브러리입니다.
참조 클래스 로더 누수 : 지칠대로 지친 "java.lang.OutOfMemoryError와 : PermGen 공간"예외 , 특히 그 후속 게시물을 .
사람들이 흔히 저지르는 실수는 힙 공간과 permgen 공간이 동일하다고 생각하는 것입니다. 힙에 많은 공간이 남아 있지만 여전히 permgen의 메모리가 부족할 수 있습니다.
PermGen에서 OutofMemory의 일반적인 원인은 ClassLoader입니다. 클래스가 JVM에로드 될 때마다 클래스 로더와 함께 모든 메타 데이터가 PermGen 영역에 유지되며 클래스를로드 한 클래스 로더가 가비지 수집 준비가되면 가비지 수집됩니다. Classloader가로드 한 모든 클래스보다 메모리 누수가 발생하는 경우 메모리에 남아 두 번 반복하면 permGen의 메모리가 부족하게됩니다. 전형적인 예는 Tomcat의 Java.lang.OutOfMemoryError : PermGen Space입니다 .
이제이를 해결하는 두 가지 방법이 있습니다.
1. 메모리 누수의 원인을 찾거나 메모리 누수가있는 경우.
JVM의 PARAM를 사용하여 PermGen 공간의 2. 크기 증가 -XX:MaxPermSize
와 -XX:PermSize
.
자세한 내용은 Java 의 2 Java.lang.OutOfMemoryError 솔루션을 확인할 수도 있습니다 .
-XX:MaxPermSize and -XX:PermSize
?? 찾을 수 없습니다 catalina.bat
. 내 바람둥이 버전은 5.5.26
입니다.
-XX:MaxPermSize=128m
Sun JVM에 대해 명령 행 매개 변수 를 사용하십시오 (필요한 크기에 따라 128을 대체 함).
시도 -XX:MaxPermSize=256m
하고 지속되면 시도하십시오-XX:MaxPermSize=512m
XX:MaxPermSize=1024m
:)
나는 추가 -XX: MaxPermSize = 128m
로 (당신이 가장 적합한 실험 할 수있다) VM 인수 내가 이클립스 IDE를 사용하고있다. 대부분의 JVM에서 기본 PermSize 는 약 64MB 로 프로젝트에 클래스가 너무 많거나 많은 수의 문자열이 있으면 메모리가 부족합니다.
일식의 경우 answer에 설명되어 있습니다.
1 단계 : 서버 탭 에서 Tomcat 서버를 두 번 클릭하십시오.
2 단계 : Launch Conf를 열고-XX: MaxPermSize = 128m
기존 VM 인수 끝에 추가 합니다 .
복잡한 웹 응용 프로그램을 배포 및 배포 취소 하면서이 문제에 대해 머리를 숙이고 설명과 솔루션을 추가 할 것이라고 생각했습니다.
Apache Tomcat에 응용 프로그램을 배포하면 해당 응용 프로그램에 대해 새로운 ClassLoader가 생성됩니다. 그런 다음 ClassLoader를 사용하여 모든 응용 프로그램 클래스를로드하고 배포 취소시 모든 것이 잘 사라집니다. 그러나 실제로는 그렇게 간단하지 않습니다.
웹 응용 프로그램의 수명 동안 생성 된 하나 이상의 클래스는 정적 참조를 보유하고 있습니다.이 참조는 어딘가에서 ClassLoader를 참조합니다. 참조는 원래 정적이므로 가비지 수집이 많으면이 참조를 정리하지 않습니다. ClassLoader 및로드 된 모든 클래스는 여기에 있습니다.
그리고 몇 번의 재배치 후에 OutOfMemoryError가 발생합니다.
이제 이것은 상당히 심각한 문제가되었습니다. 각 재배포 후에 Tomcat을 다시 시작할 수 있지만 재배포되는 응용 프로그램이 아니라 전체 서버가 다운되어 종종 실행되지 않는 경우가 있습니다.
대신 Apache Tomcat 6.0에서 작동하는 코드 솔루션을 작성했습니다. 다른 응용 프로그램 서버에서 테스트 한 적이 없으며 다른 응용 프로그램 서버에서 수정하지 않으면 작동하지 않을 가능성이 높습니다 .
또한 개인적으로이 코드를 싫어 하고 기존 코드를 적절한 종료 및 정리 방법을 사용하도록 변경할 수있는 경우이 코드를 "빠른 수정"으로 사용해서는 안된다고 말하고 싶습니다 . 이것이 사용되어야 할 유일한 시간은 코드가 의존하는 외부 라이브러리가있는 경우 (내 경우에는 RADIUS 클라이언트였습니다) 자체 정적 참조를 정리하는 수단을 제공하지 않습니다.
어쨌든, 코드와 함께. 서블릿의 destroy 메소드 또는 servletContextListener의 contextDestroyed 메소드와 같이 애플리케이션이 배치 해제중인 지점에서 호출해야합니다.
//Get a list of all classes loaded by the current webapp classloader
WebappClassLoader classLoader = (WebappClassLoader) getClass().getClassLoader();
Field classLoaderClassesField = null;
Class clazz = WebappClassLoader.class;
while (classLoaderClassesField == null && clazz != null) {
try {
classLoaderClassesField = clazz.getDeclaredField("classes");
} catch (Exception exception) {
//do nothing
}
clazz = clazz.getSuperclass();
}
classLoaderClassesField.setAccessible(true);
List classes = new ArrayList((Vector)classLoaderClassesField.get(classLoader));
for (Object o : classes) {
Class c = (Class)o;
//Make sure you identify only the packages that are holding references to the classloader.
//Allowing this code to clear all static references will result in all sorts
//of horrible things (like java segfaulting).
if (c.getName().startsWith("com.whatever")) {
//Kill any static references within all these classes.
for (Field f : c.getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers())
&& !Modifier.isFinal(f.getModifiers())
&& !f.getType().isPrimitive()) {
try {
f.setAccessible(true);
f.set(null, null);
} catch (Exception exception) {
//Log the exception
}
}
}
}
}
classes.clear();
java.lang.OutOfMemoryError: PermGen
공간이 메시지는 메모리에 영구 세대의 면적이 소진되어 있음을 나타냅니다.
모든 Java 응용 프로그램은 제한된 양의 메모리를 사용할 수 있습니다. 특정 응용 프로그램에서 사용할 수있는 정확한 메모리 양은 응용 프로그램 시작 중에 지정됩니다.
Java 메모리는 다음 이미지에서 볼 수있는 다른 영역으로 구분됩니다.
메타 스페이스 : 새로운 메모리 공간이 탄생
JDK 8 HotSpot JVM은 이제 클래스 메타 데이터를 표현하기 위해 기본 메모리를 사용하고 있으며이를 메타 스페이스라고합니다. Oracle JRockit 및 IBM JVM과 유사합니다.
좋은 소식은 더 이상 java.lang.OutOfMemoryError: PermGen
공간 문제가 없으며 Java_8_Download 이상을 사용하여 더 이상이 메모리 공간을 조정하고 모니터링 할 필요 가 없다는 것을 의미 합니다.
가장 먼저 할 수있는 일은 영구 생성 힙 공간의 크기를 늘리는 것입니다. 언급 된 것처럼 영구 생성 힙 공간은 일반 Java 힙 공간과 완전히 분리되어 있으므로이 인수 세트는 일반적인 –Xms (초기 힙 크기 설정) 및 –Xmx (최대 힙 크기 설정) JVM 인수로 수행 할 수 없습니다. 이 정규 Java 힙 공간을위한 공간 그러나 영구 생성 힙의 크기를 더 크게 만들기 위해 (적어도 Sun / OpenJDK jvms와 함께) 사용할 수있는 유사한 인수가 있습니다.
-XX:MaxPermSize=128m
기본값은 64m입니다.
이를 잘 처리하는 또 다른 방법은 클래스를 언로드하여 PermGen이 절대로 소모되지 않도록하는 것입니다.
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
그런 것들이 과거에 나에게 마술로 작용했습니다. 그러나 permgen 스윕은 모든 요청이나 그 라인을 따라 무언가를 추가로 요청하기 때문에 성능을 떨어 뜨릴 수 있습니다. 트레이드 오프와 사용의 균형을 유지해야합니다.
이 오류의 세부 사항을 찾을 수 있습니다.
http://faisalbhagat.blogspot.com/2014/09/java-outofmemoryerror-permgen.html
또는 permgen을 처리하는 JRockit으로 전환하여 sun의 jvm과 다르게 할 수 있습니다. 일반적으로 성능도 향상됩니다.
http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html
java.lang.OutOfMemoryError: There is insufficient native memory
대신 얻을 것이다 .
우리가 여기서 이야기하는 문제가 있었는데, 시나리오는 eclipse-helios + tomcat + jsf이며 당신이하고있는 일은 tomcat에 간단한 응용 프로그램을 배포하는 것입니다. 나는 여기에 같은 문제를 보이고 있었고, 다음과 같이 해결했다.
이클립스에서 서버 탭으로 이동하면 내 경우 tomcat 7.0에 등록 된 서버를 두 번 클릭하면 파일 서버 일반 등록 정보가 열립니다. "일반 정보" 섹션에서 " 시작 구성 열기" 링크를 클릭 하면이 두 항목 끝에 추가 된 VM 인수의 인수 탭에서 서버 옵션 실행이 열립니다.
-XX: MaxPermSize = 512m
-XX: PermSize = 512m
그리고 준비.
요즘 가장 간단한 대답은 Java 8을 사용하는 것입니다.
더 이상 PermGen 공간 전용 메모리를 예약하지 않으므로 PermGen 메모리가 일반 메모리 풀과 혼합 될 수 있습니다.
-XXPermGen...=...
Java 8에서 아무것도하지 않는다고 불평하지 않으려면 비표준 JVM 시작 매개 변수를 모두 제거 해야합니다.
코드를 실행할 공간을 제공하지 않고 jvm 대신 공간을 사용하여 Perm gen 공간 오류가 발생합니다.
UNIX 운영 체제에서이 문제점에 대한 최상의 솔루션은 bash 파일에서 일부 구성을 변경하는 것입니다. 다음 단계는 문제를 해결합니다.
gedit .bashrc
터미널에서 명령 을 실행하십시오 .
JAVA_OTPS
다음 값으로 변수를 작성하십시오 .
export JAVA_OPTS="-XX:PermSize=256m -XX:MaxPermSize=512m"
bash 파일을 저장하십시오. 터미널에서 exec bash 명령을 실행하십시오. 서버를 다시 시작하십시오.
이 접근법이 귀하의 문제에 도움이되기를 바랍니다. 8보다 낮은 Java 버전을 사용하는 경우이 문제가 가끔 발생합니다. 그러나 Java 8을 사용하면 문제가 발생하지 않습니다.
또한 webapp에서 log4j를 사용하는 경우 log4j documentation 에서이 단락을 확인하십시오 .
를 사용하는 경우 PropertyConfigurator.configureAndWatch("log4j.properties")
webapp를 배포 취소 할 때 메모리 누수가 발생 하는 것 같습니다 .
나는 최대 절전 모드 + 이클립스 RCP의 조합을 사용 -XX:MaxPermSize=512m
하고 사용해 보았고 -XX:PermSize=512m
그것은 나를 위해 일하는 것 같습니다.
나는 몇 가지 답변을 시도했으며 마지막으로 일을 한 유일한 것은 pom의 컴파일러 플러그인을위한이 구성이었습니다.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<fork>true</fork>
<meminitial>128m</meminitial>
<maxmem>512m</maxmem>
<source>1.6</source>
<target>1.6</target>
<!-- prevent PermGen space out of memory exception -->
<!-- <argLine>-Xmx512m -XX:MaxPermSize=512m</argLine> -->
</configuration>
</plugin>
이것이 도움이 되길 바랍니다.
나는 똑같은 문제에 부딪 쳤지 만 불행히도 제안 된 솔루션 중 어느 것도 실제로 나를 위해 일하지 않았습니다. 배포하는 동안 문제가 발생하지 않았으며 핫 배포를 수행하지 않았습니다.
필자의 경우 웹 응용 프로그램을 실행하는 동안 같은 시점에 데이터베이스에 연결하는 동안 최대 절전 모드를 통해 문제가 발생했습니다.
이 링크 (앞서 언급)는 문제를 해결하기에 충분한 내부 정보를 제공했습니다. jdbc- (mysql) 드라이버를 WEB-INF에서 jre / lib / ext / 폴더로 옮기면 문제가 해결 된 것 같습니다. 최신 JRE로 업그레이드하려면 드라이버를 다시 설치해야하므로 이상적인 솔루션은 아닙니다. 비슷한 문제를 일으킬 수있는 또 다른 후보는 log4j이므로 해당 후보를 옮기고 싶을 수도 있습니다.
이 경우 첫 번째 단계는 GC가 PermGen에서 클래스를 언로드 할 수 있는지 확인하는 것입니다. 표준 JVM은 이와 관련하여 다소 보수적입니다. 클래스는 영원히 살기 위해 탄생했습니다. 따라서 일단로드되면 클래스는 더 이상 코드를 사용하지 않아도 메모리에 유지됩니다. 애플리케이션이 많은 클래스를 동적으로 작성하고 생성 된 클래스가 더 이상 필요하지 않은 경우 문제가 될 수 있습니다. 이러한 경우 JVM이 클래스 정의를 언로드하도록 허용하면 도움이 될 수 있습니다. 시작 스크립트에 하나의 구성 매개 변수 만 추가하면됩니다.
-XX:+CMSClassUnloadingEnabled
기본적으로 이것은 false로 설정되어 있으므로이를 활성화하려면 Java 옵션에서 다음 옵션을 명시 적으로 설정해야합니다. CMSClassUnloadingEnabled를 활성화하면 GC가 PermGen을 스윕하고 더 이상 사용되지 않는 클래스를 제거합니다. 이 옵션은 UseConcMarkSweepGC가 아래 옵션을 사용하여 활성화 된 경우에만 작동합니다. 따라서 ParallelGC 또는 God forbider Serial GC를 실행할 때 다음을 지정하여 GC를 CMS로 설정했는지 확인하십시오.
-XX:+UseConcMarkSweepGC
Tomcat에 더 많은 메모리를 할당하는 것은 올바른 해결책이 아닙니다.
올바른 솔루션은 컨텍스트가 삭제되고 다시 작성된 후 정리를 수행하는 것입니다 (핫 배치). 해결책은 메모리 누수를 막는 것입니다.
Tomcat / Webapp 서버가 드라이버 등록 해제 (JDBC)에 실패했다는 메시지를 표시하면 등록을 취소하십시오. 메모리 누수가 중단됩니다.
ServletContextListener를 작성하고 web.xml에서 구성 할 수 있습니다. 다음은 샘플 ServletContextListener입니다.
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.log4j.Logger;
import com.mysql.jdbc.AbandonedConnectionCleanupThread;
/**
*
* @author alejandro.tkachuk / calculistik.com
*
*/
public class AppContextListener implements ServletContextListener {
private static final Logger logger = Logger.getLogger(AppContextListener.class);
@Override
public void contextInitialized(ServletContextEvent arg0) {
logger.info("AppContextListener started");
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
logger.info("AppContextListener destroyed");
// manually unregister the JDBC drivers
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
logger.info(String.format("Unregistering jdbc driver: %s", driver));
} catch (SQLException e) {
logger.info(String.format("Error unregistering driver %s", driver), e);
}
}
// manually shutdown clean up threads
try {
AbandonedConnectionCleanupThread.shutdown();
logger.info("Shutting down AbandonedConnectionCleanupThread");
} catch (InterruptedException e) {
logger.warn("SEVERE problem shutting down AbandonedConnectionCleanupThread: ", e);
e.printStackTrace();
}
}
}
그리고 여기 web.xml에서 구성하십시오.
<listener>
<listener-class>
com.calculistik.mediweb.context.AppContextListener
</listener-class>
</listener>
경우 당신은 매개 변수를 설정 한 후, 이클립스 IDE에서이지고
--launcher.XXMaxPermSize
, -XX:MaxPermSize
등, 같은 오류가 발생하는 경우 여전히 대부분의 가능성이 일식 일부가 설치되어있는 것 JRE의 버그 버전을 사용하고 있다는 것입니다 타사 응용 프로그램을 기본값으로 설정합니다. 이 버기 버전은 PermSize 매개 변수를 선택하지 않으므로 설정 한 내용에 관계없이 이러한 메모리 오류가 계속 발생합니다. 따라서 eclipse.ini에서 다음 매개 변수를 추가하십시오.
-vm <path to the right JRE directory>/<name of javaw executable>
또한 Eclipse의 환경 설정에서 기본 JRE를 올바른 Java 버전으로 설정했는지 확인하십시오.
나를 위해 일한 유일한 방법은 JRockit JVM을 사용하는 것입니다. MyEclipse 8.6이 있습니다.
JVM의 힙은 실행중인 Java 프로그램에서 생성 된 모든 오브젝트를 저장합니다. Java는 new
연산자를 사용하여 오브젝트를 작성하고 새 오브젝트에 대한 메모리는 런타임시 힙에 할당됩니다. 가비지 콜렉션은 더 이상 프로그램에서 참조하지 않는 오브젝트에 포함 된 메모리를 자동으로 해제하는 메커니즘입니다.
비슷한 문제가 발생했습니다. 내 JDK 7 + Maven 3.0.2 + Struts 2.0 + Google GUICE 의존성 주입 기반 프로젝트입니다.
mvn clean package
명령을 실행하려고 할 때마다 다음과 같은 오류가 표시되고 "BUILD FAILURE"가 발생했습니다.
org.apache.maven.surefire.util.SurefireReflectionException : java.lang.reflect.InvocationTargetException; 중첩 예외는 java.lang.reflect.InvocationTargetException입니다. null java.lang.reflect.InvocationTargetException 원인 : java.lang.OutOfMemoryError : PermGen 공간
위의 유용한 팁과 트릭을 모두 시도했지만 불행히도 아무도 나를 위해 일하지 않았습니다. 나를 위해 일한 것은 아래에 단계별로 설명되어 있습니다 : =>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
요소를 추가 한 다음 아래에 표시된 것처럼 <argLine>
하위 요소를 추가하십시오.-Xmx512m -XX:MaxPermSize=256m
<configuration>
<argLine>-Xmx512m -XX:MaxPermSize=256m</argLine>
</configuration>
그것이 도움이되기를 바랍니다, 행복한 프로그래밍 :)