"java.lang.OutOfMemoryError : PermGen space"오류 처리


1222

최근에 웹 응용 프로그램 에서이 오류가 발생했습니다.

java.lang.OutOfMemoryError : PermGen 공간

Tomcat 6 및 JDK 1.6에서 실행되는 일반적인 Hibernate / JPA + IceFaces / JSF 응용 프로그램입니다. 분명히 응용 프로그램을 몇 번 재배치 한 후에 발생할 수 있습니다.

그것을 일으키는 원인과 그것을 피하기 위해 무엇을 할 수 있습니까? 문제를 어떻게 해결합니까?


나는 이것을 몇 시간 동안 싸웠지 만 좋은 소식은 없습니다. 내 관련 질문을 참조하십시오. stackoverflow.com/questions/1996088/… 여전히 메모리 누수가있을 수 있습니다. 예를 들어 WebAppClassLoader가 가비지 수집되지 않기 때문에 클래스가 가비지 수집되지 않습니다 (지우지 않은 외부 참조가 있음). PermGen을 늘리면 OutOfMemoryError 만 지연되고 클래스 가비지 수집을 허용하는 것이 전제 조건이지만 클래스 로더에 여전히 참조가있는 경우 클래스를 가비지 수집하지 않습니다.
Eran Medan

display taglib 추가 시이 오류가 발생했습니다 . 그렇게 제거하면 오류가 해결되었습니다. 왜 그래?
masT

그리고 당신은 어떻게 그것에 빠졌습니까?
Thorbjørn Ravn Andersen

13
JDK 1.8 사용 : þ : MetaSpace에 오신 것을 환영합니다
Rytek

Windows를 사용하는 경우 구성 파일에서 플래그를 수동으로 설정하지 말고 다음 지시 사항을 따르십시오. 이렇게하면 런타임 중에 Tomcat이 레지스트리의 값을 호출하도록 올바르게 설정합니다. stackoverflow.com/questions/21104340/…
MacGyver

답변:


563

해결책은 Tomcat이 시작될 때 이러한 플래그를 JVM 명령 행에 추가하는 것입니다.

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Tomcat 서비스를 종료 한 다음 Tomcat / bin 디렉토리로 이동하여 tomcat6w.exe를 실행하면됩니다. "Java"탭에서 "Java 옵션"상자에 인수를 추가하십시오. "확인"을 클릭 한 다음 서비스를 다시 시작하십시오.

오류가 발생 하면 지정된 서비스가 설치된 서비스로 존재하지 않습니다 .

tomcat6w //ES//servicename

여기서 servicename 은 services.msc에 표시된 서버 이름입니다.

출처 : Eric의 Agile Answers 에 대한 orx의 의견 .


39
아래 기사는 -XX : + UseConcMarkSweepGC 및 -XX : MaxPermSize = 128m을 제안합니다. my.opera.com/karmazilla/blog/2007/03/13/…
Taylor Leese 님이

30
-XX : + CMSPermGenSweepingEnabled이 옵션은 성능을 저하시킵니다. 시스템에서 각 요청이 평소보다 3 배 더 오래 걸립니다. 주의해서 사용하십시오.
Eldelshell

10
나를 위해 일했습니다-감사합니다-Tomcat6으로 Ubuntu 10.10 에서이 작업을 수행하고 있습니다-새 파일 /usr/share/tomcat6/bin/setenv.sh를 만들고 다음 줄을 추가했습니다. JAVA_OPTS = "-Xms256m -Xmx512m- XX : + CMSClassUnloadingEnabled -XX : + CMSPermGenSweepingEnabled "-sudo /etc/init.d/tomcat6 start
sami

24
tomcat 6.0.29 시작시 catalina.out 로그 파일에서 : "향후 CMSPermGenSweepingEnabled 대신 CMSClassUnloadingEnabled를 사용하십시오"
knb

222
우선이 플래그들이 실제로 무엇을하는지 설명하는 것이 좋습니다. "그것을 즐기고 즐기기"만으로는 충분하지 않습니다.
Nikem

251

보다 시도하는 -XX:MaxPermSize=128M것이 좋습니다 -XX:MaxPermGen=128M.

이 메모리 풀의 정확한 사용법을 알 수는 없지만 JVM에로드 된 클래스 수와 관련이 있습니다. (톰캣에 클래스 언로드를 활성화하면 문제를 해결할 수 있습니다.) 응용 프로그램이 실행시 클래스를 생성하고 컴파일하는 경우 기본보다 큰 메모리 풀이 필요할 가능성이 큽니다.


9
실제로 이것은 OOMError 만 연기합니다. frankkieviet 블로그에 대한 두 개의 링크로 anon에서 시작한 아래 답변을 참조하십시오.
Rade_303

이러한 옵션은 여기에 설명되어 있습니다. oracle.com/technetwork/java/javase/tech/…
amos

153

여러 배포 후 발생하는 앱 서버 PermGen 오류는 컨테이너가 이전 앱의 클래스 로더에 보유한 참조에 의해 발생합니다. 예를 들어, 사용자 정의 로그 레벨 클래스를 사용하면 앱 서버의 클래스 로더가 참조를 보유하게됩니다. jmap 및 jhat과 같은 최신 (JDK6 +) JVM 분석 도구를 사용하여 앱에서 어떤 클래스가 계속 유지되는지 확인하고 사용을 재 설계 또는 제거하여 이러한 클래스 간 로더 누수를 감지 할 수 있습니다. 일반적인 용의자는 데이터베이스, 로거 및 기타 기본 프레임 워크 수준 라이브러리입니다.

참조 클래스 로더 누수 : 지칠대로 지친 "java.lang.OutOfMemoryError와 : PermGen 공간"예외 , 특히 그 후속 게시물을 .


3
이것은 문제에 대한 진정한 해결책이며 경우에 따라 구현하기가 너무 어려울 수도 있습니다.
Rade_303

또 다른 좋은 소스는 people.apache.org/~markt/presentations/…(Tomcat 릴리스 관리자의 !!)입니다.
gavenkoa

22
이 이론적으로 질문에 대답 할 수 있습니다 동안, 바람직 할 것이다 여기에 대한 대답의 본질적인 부분을 포함하고 참조 할 수 있도록 링크를 제공합니다.
Joachim Sauer

68

사람들이 흔히 저지르는 실수는 힙 공간과 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 솔루션을 확인할 수도 있습니다 .


3
매개 변수를 전달하는 방법 -XX:MaxPermSize and -XX:PermSize?? 찾을 수 없습니다 catalina.bat. 내 바람둥이 버전은 5.5.26입니다.
Deckard

클래스 로더의 메모리 누수를 찾는 방법은 무엇입니까? 도구를 추천하십니까?
아 미트

도구 권장 사항에 대해서는 @amit,이 질문에 대한 커뮤니티 위키 답변을 참조하십시오.
Barett

@Deckard는 Tomcat / bin 디렉토리로 이동하여 tomcat6w.exe를 실행합니다. "Java"탭에서 "Java 옵션"상자에 인수를 추가하십시오. "확인"을 클릭하십시오
Zeb

43

-XX:MaxPermSize=128mSun JVM에 대해 명령 행 매개 변수 를 사용하십시오 (필요한 크기에 따라 128을 대체 함).


9
유일한 문제는 당신이 피할 수없는 것을 지연시키고 있다는 것입니다. 어느 시점에서 헤드 룸이 부족할 것입니다. 훌륭한 실용적인 솔루션이지만 영구적으로 해결되지는 않습니다.
Tim Howland

Eclipse에서도 동일한 일이 발생하며 동적 클래스 로딩이 많을 때마다 발생합니다. 클래스 로더는 영원 토록
Matt

1
특히 대규모 Hudson 작업을 실행할 때 PermGen이 부족했습니다 ...이 문제가 해결되었습니다.
HDave

10
@ TimHowland, 근본 원인이 클래스 로더 누수가 아닌 경우 웹 앱에 너무 많은 클래스 / 정적 데이터가 있으면 영구적 인 수정이 될 수 있습니다.
Péter Török

소스에서 jenkins / hudson을 빌드 할 때 HDave와 동일한 문제가 발생했습니다.
louisgab

38

시도 -XX:MaxPermSize=256m하고 지속되면 시도하십시오-XX:MaxPermSize=512m


56
그래도 계속 시도하면 XX:MaxPermSize=1024m:)
igo

38
그리고 여전히 지속되면 XX : MaxPermSize = 2048m :)
Thomas

16
그래도 계속되면 응용 프로그램을 다시 생각하십시오! 또는 XX : MaxPermSize = 4096m :)
Jonathan Airey

17
당신은 또한 8,192m 시도하지만 과잉의 비트 이잖아 수
제이 섹 Pietal에게

12
실제로 과잉-640KB이면 누구나 충분합니다!
Joel Purra

28

나는 추가 -XX: MaxPermSize = 128m 로 (당신이 가장 적합한 실험 할 수있다) VM 인수 내가 이클립스 IDE를 사용하고있다. 대부분의 JVM에서 기본 PermSize 는 약 64MB 로 프로젝트에 클래스가 너무 많거나 많은 수의 문자열이 있으면 메모리가 부족합니다.

일식의 경우 answer에 설명되어 있습니다.

1 단계 : 서버 탭 에서 Tomcat 서버를 두 번 클릭하십시오.

여기에 이미지 설명을 입력하십시오

2 단계 : Launch Conf를 열고-XX: MaxPermSize = 128m 기존 VM 인수 끝에 추가 합니다 .

여기에 이미지 설명을 입력하십시오


1
가장 자세한 답변을 보내 주셔서 감사합니다. (참고 : "구성 시작"을 클릭하여 "구성 편집"창을 열 수 있지만 다음 매개 변수를 사용했습니다. "-XX : + CMSClassUnloadingEnabled -XX : + CMSPermGenSweepingEnabled"
Chris Sim

23

복잡한 웹 응용 프로그램을 배포 및 배포 취소 하면서이 문제에 대해 머리를 숙이고 설명과 솔루션을 추가 할 것이라고 생각했습니다.

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();

나는 이것을 쓴지 8 년이 지났다는 것을 알고 있지만, 그 사이와 지금은 더 깊은 근본 원인과 해결책을 찾았습니다. 이것은 webapp 내의 모든 클래스가 컨텍스트 클래스 로더가 소유하는 반면 시작 및 종료 콜백을 호출하는 스레드는 상위 클래스 로더가 소유한다는 것입니다. 이는 종료 코드가 스레드 로컬 변수를 초기화하는 경우 상위 클래스 로더가 컨텍스트 클래스 로더에 대한 참조를 보유하게하여 양호한 정리를 방해 함을 의미합니다.
Edward Torbett

운 좋게도 매우 간단한 수정이 있습니다. 현재 shutdown 메소드에있는 모든 코드를 새로운 Thread 객체의 run 메소드로 옮기십시오. 그런 다음 종료 방법에서이 스레드를 시작하고 완료 될 때까지 기다리십시오. 정리 코드는 동일하게 실행되지만 스레드 로컬 변수는 누출 대신 컨텍스트 클래스 로더에 바인딩 된 상태로 유지됩니다.
Edward Torbett

20

java.lang.OutOfMemoryError: PermGen공간이 메시지는 메모리에 영구 세대의 면적이 소진되어 있음을 나타냅니다.

모든 Java 응용 프로그램은 제한된 양의 메모리를 사용할 수 있습니다. 특정 응용 프로그램에서 사용할 수있는 정확한 메모리 양은 응용 프로그램 시작 중에 지정됩니다.

Java 메모리는 다음 이미지에서 볼 수있는 다른 영역으로 구분됩니다.

여기에 이미지 설명을 입력하십시오

메타 스페이스 : 새로운 메모리 공간이 탄생

JDK 8 HotSpot JVM은 이제 클래스 메타 데이터를 표현하기 위해 기본 메모리를 사용하고 있으며이를 메타 스페이스라고합니다. Oracle JRockit 및 IBM JVM과 유사합니다.

좋은 소식은 더 이상 java.lang.OutOfMemoryError: PermGen공간 문제가 없으며 Java_8_Download 이상을 사용하여 더 이상이 메모리 공간을 조정하고 모니터링 할 필요 가 없다는 것을 의미 합니다.


17

1) PermGen 메모리 크기 늘리기

가장 먼저 할 수있는 일은 영구 생성 힙 공간의 크기를 늘리는 것입니다. 언급 된 것처럼 영구 생성 힙 공간은 일반 Java 힙 공간과 완전히 분리되어 있으므로이 인수 세트는 일반적인 –Xms (초기 힙 크기 설정) 및 –Xmx (최대 힙 크기 설정) JVM 인수로 수행 할 수 없습니다. 이 정규 Java 힙 공간을위한 공간 그러나 영구 생성 힙의 크기를 더 크게 만들기 위해 (적어도 Sun / OpenJDK jvms와 함께) 사용할 수있는 유사한 인수가 있습니다.

 -XX:MaxPermSize=128m

기본값은 64m입니다.

2) 스위프 활성화

이를 잘 처리하는 또 다른 방법은 클래스를 언로드하여 PermGen이 절대로 소모되지 않도록하는 것입니다.

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

그런 것들이 과거에 나에게 마술로 작용했습니다. 그러나 permgen 스윕은 모든 요청이나 그 라인을 따라 무언가를 추가로 요청하기 때문에 성능을 떨어 뜨릴 수 있습니다. 트레이드 오프와 사용의 균형을 유지해야합니다.

이 오류의 세부 사항을 찾을 수 있습니다.

http://faisalbhagat.blogspot.com/2014/09/java-outofmemoryerror-permgen.html


@faisalbhagat의 위대한 포스트 faisalbhagat.blogspot.com/2014/09/...
leomeurer

옵션 2는 훌륭하지만 프로덕션 환경에서는 사용해서는 안된다는 경고 만 표시됩니다. 일반적으로 개발 환경에만 유지하는 것이 가장 좋습니다. 그러나 PermGen은 Java 8 openjdk.java.net/jeps/122에서
hdost


14

우리가 여기서 이야기하는 문제가 있었는데, 시나리오는 eclipse-helios + tomcat + jsf이며 당신이하고있는 일은 tomcat에 간단한 응용 프로그램을 배포하는 것입니다. 나는 여기에 같은 문제를 보이고 있었고, 다음과 같이 해결했다.

이클립스에서 서버 탭으로 이동하면 내 경우 tomcat 7.0에 등록 된 서버를 두 번 클릭하면 파일 서버 일반 등록 정보가 열립니다. "일반 정보" 섹션에서 " 시작 구성 열기" 링크를 클릭 하면이 두 항목 끝에 추가 된 VM 인수의 인수 탭에서 서버 옵션 실행이 열립니다.

-XX: MaxPermSize = 512m
-XX: PermSize = 512m

그리고 준비.


14

요즘 가장 간단한 대답은 Java 8을 사용하는 것입니다.

더 이상 PermGen 공간 전용 메모리를 예약하지 않으므로 PermGen 메모리가 일반 메모리 풀과 혼합 될 수 있습니다.

-XXPermGen...=...Java 8에서 아무것도하지 않는다고 불평하지 않으려면 비표준 JVM 시작 매개 변수를 모두 제거 해야합니다.


안녕하세요,이 답변은 이미 주어졌습니다 : stackoverflow.com/a/22897121/505893 . 명확성을 위해 답변을 삭제하십시오. 필요한 경우 언급 한 답변을 향상시킬 수 있습니다. 감사합니다;)
푸르스름한

6
@bluish 지적 해 주셔서 감사합니다. 그러나 그 대답은 OutOfMemoryExceptions 및 유출 메타 데이터에 관해 모든 측면에서 진행됩니다. 또한 PermGen 옵션을 제거 할 때 중요한 점을 언급하지 않습니다. 간단히 말해서, 나는 대답을 향상시킬 것이라 확신하지 않지만 오히려 그것을 다시 쓰십시오. 빠른 수정만으로 주저하지는 않지만 빠른 수정보다 훨씬 많은 것처럼 보이며 원래 작성자를 화나게하는 것을 싫어합니다. 그럼에도 불구하고,이 답변 목록은 엉망인 개 저녁 식사이며 어쩌면 내 게시물을 죽이는 것이 가장 좋습니다.
Edwin Buck

8
  1. Tomcat의 bin 디렉토리에서 tomcat7w를 열거 나 시작 메뉴에 Monitor Tomcat을 입력하십시오 (다양한 서비스 정보와 함께 탭 창이 열립니다).
  2. Java 옵션 텍스트 영역에서 다음 행을 추가하십시오.

    -XX:MaxPermSize=128m
  3. 초기 메모리 풀을 1024로 설정하십시오 (선택 사항).
  4. 최대 메모리 풀을 1024로 설정하십시오 (선택 사항).
  5. 확인을 클릭하십시오.
  6. Tomcat 서비스를 다시 시작하십시오.

6

코드를 실행할 공간을 제공하지 않고 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을 사용하면 문제가 발생하지 않습니다.


5

실제 메모리 누수가있는 경우 영구 생성 크기를 늘리거나 GC 매개 변수를 조정해도 도움이되지 않습니다. 응용 프로그램 또는 타사 라이브러리가 사용하는 경우 클래스 로더가 누수되면 실제로 누출되는 유일한 해결책은이 누수를 찾아서 해결하는 것입니다. 최근 도움이 될만한 도구가 많이 있습니다. 최근 Plumbr 은 필요한 기능을 갖춘 새 버전을 출시했습니다.


5

또한 webapp에서 log4j를 사용하는 경우 log4j documentation 에서이 단락을 확인하십시오 .

를 사용하는 경우 PropertyConfigurator.configureAndWatch("log4j.properties")webapp를 배포 취소 할 때 메모리 누수가 발생 하는 것 같습니다 .


4

나는 최대 절전 모드 + 이클립스 RCP의 조합을 사용 -XX:MaxPermSize=512m하고 사용해 보았고 -XX:PermSize=512m그것은 나를 위해 일하는 것 같습니다.


4

설정하십시오 -XX:PermSize=64m -XX:MaxPermSize=128m. 나중에 당신은 또한 증가를 시도 할 수 있습니다 MaxPermSize. 그것이 효과가 있기를 바랍니다. 나도 마찬가지입니다. 설정 MaxPermSize은 나에게 효과가 없었습니다.


4

나는 몇 가지 답변을 시도했으며 마지막으로 일을 한 유일한 것은 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>

이것이 도움이 되길 바랍니다.


maven-compiler-plugin 2.4에서는 "argLine"을 인식하지 못합니다. <compilerArgument> -XX : MaxPermSize = 256m </ compilerArgument> [ERROR] javac 실행에 실패했지만 오류를 구문 분석 할 수 없습니다. javac : invalid flag : -XX : MaxPermSize = 256m 사용법 : javac <옵션> <소스 파일>
Alex

컴파일 단계에 permgen이 부족하면 maven-compiler-plugin에서 <compilerArgument>를 설정하십시오. 단위 테스트에서 maven-surefire-plugin
qwerty

4

나에게도 이것을 해결했다. 그러나 서블릿 재시작 시간이 훨씬 더 나쁘다는 것을 알았으므로 프로덕션에서는 더 좋았지 만 개발에는 어려움이있었습니다.


3

메모리 구성은 앱의 특성에 따라 다릅니다.

뭐하는거야?

이전에 거래 한 금액은 얼마입니까?

얼마나 많은 데이터를로드하고 있습니까?

기타

기타

기타

아마도 앱을 프로파일 링하고 앱에서 일부 모듈 정리를 시작할 수 있습니다.

분명히 응용 프로그램을 몇 번 재배치 한 후에 발생할 수 있습니다.

Tomcat은 핫 배포가 있지만 메모리를 소비합니다. 컨테이너를 잠시 다시 시작해보십시오. 또한 프로덕션 모드에서 실행하는 데 필요한 메모리 양을 알아야합니다.이 연구에 적합한 시간입니다.


3

그들은 Tomcat (6.0.28 또는 6.0.29)의 최신 개정판이 서블릿 재배치 작업을 훨씬 잘 처리한다고 말합니다 .


3

나는 똑같은 문제에 부딪 쳤지 만 불행히도 제안 된 솔루션 중 어느 것도 실제로 나를 위해 일하지 않았습니다. 배포하는 동안 문제가 발생하지 않았으며 핫 배포를 수행하지 않았습니다.

필자의 경우 웹 응용 프로그램을 실행하는 동안 같은 시점에 데이터베이스에 연결하는 동안 최대 절전 모드를 통해 문제가 발생했습니다.

이 링크 (앞서 언급)는 문제를 해결하기에 충분한 내부 정보를 제공했습니다. jdbc- (mysql) 드라이버를 WEB-INF에서 jre / lib / ext / 폴더로 옮기면 문제가 해결 된 것 같습니다. 최신 JRE로 업그레이드하려면 드라이버를 다시 설치해야하므로 이상적인 솔루션은 아닙니다. 비슷한 문제를 일으킬 수있는 또 다른 후보는 log4j이므로 해당 후보를 옮기고 싶을 수도 있습니다.


jre / lib / ext에 드라이버를 포함하지 않으려면 컨테이너 시작 클래스 경로에 드라이버를 포함 시켜서 동일한 결과를 얻을 수 있습니다. java -cp /path/to/jdbc-mysql-driver.jar:/path/to/container/bootstrap.jar container.Start
Scot

3

이 경우 첫 번째 단계는 GC가 PermGen에서 클래스를 언로드 할 수 있는지 확인하는 것입니다. 표준 JVM은 이와 관련하여 다소 보수적입니다. 클래스는 영원히 살기 위해 탄생했습니다. 따라서 일단로드되면 클래스는 더 이상 코드를 사용하지 않아도 메모리에 유지됩니다. 애플리케이션이 많은 클래스를 동적으로 작성하고 생성 된 클래스가 더 이상 필요하지 않은 경우 문제가 될 수 있습니다. 이러한 경우 JVM이 클래스 정의를 언로드하도록 허용하면 도움이 될 수 있습니다. 시작 스크립트에 하나의 구성 매개 변수 만 추가하면됩니다.

-XX:+CMSClassUnloadingEnabled

기본적으로 이것은 false로 설정되어 있으므로이를 활성화하려면 Java 옵션에서 다음 옵션을 명시 적으로 설정해야합니다. CMSClassUnloadingEnabled를 활성화하면 GC가 PermGen을 스윕하고 더 이상 사용되지 않는 클래스를 제거합니다. 이 옵션은 UseConcMarkSweepGC가 아래 옵션을 사용하여 활성화 된 경우에만 작동합니다. 따라서 ParallelGC 또는 God forbider Serial GC를 실행할 때 다음을 지정하여 GC를 CMS로 설정했는지 확인하십시오.

-XX:+UseConcMarkSweepGC

3

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>  

2

6.0.29를 실행 중이고 모든 옵션을 설정 한 후에도 동일한 문제가 발생하기 때문에 "그들"이 잘못되었습니다. Tim Howland가 위에서 말했듯이 이러한 옵션은 피할 수없는 것입니다. 다시 배포 할 때마다 오류가 발생하기 전에 3 번 다시 배포 할 수 있습니다.


2

경우 당신은 매개 변수를 설정 한 후, 이클립스 IDE에서이지고 --launcher.XXMaxPermSize, -XX:MaxPermSize등, 같은 오류가 발생하는 경우 여전히 대부분의 가능성이 일식 일부가 설치되어있는 것 JRE의 버그 버전을 사용하고 있다는 것입니다 타사 응용 프로그램을 기본값으로 설정합니다. 이 버기 버전은 PermSize 매개 변수를 선택하지 않으므로 설정 한 내용에 관계없이 이러한 메모리 오류가 계속 발생합니다. 따라서 eclipse.ini에서 다음 매개 변수를 추가하십시오.

-vm <path to the right JRE directory>/<name of javaw executable>

또한 Eclipse의 환경 설정에서 기본 JRE를 올바른 Java 버전으로 설정했는지 확인하십시오.


2

나를 위해 일한 유일한 방법은 JRockit JVM을 사용하는 것입니다. MyEclipse 8.6이 있습니다.

JVM의 힙은 실행중인 Java 프로그램에서 생성 된 모든 오브젝트를 저장합니다. Java는 new연산자를 사용하여 오브젝트를 작성하고 새 오브젝트에 대한 메모리는 런타임시 힙에 할당됩니다. 가비지 콜렉션은 더 이상 프로그램에서 참조하지 않는 오브젝트에 포함 된 메모리를 자동으로 해제하는 메커니즘입니다.


2

비슷한 문제가 발생했습니다. 내 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 공간

위의 유용한 팁과 트릭을 모두 시도했지만 불행히도 아무도 나를 위해 일하지 않았습니다. 나를 위해 일한 것은 아래에 단계별로 설명되어 있습니다 : =>

  1. pom.xml로 이동하십시오
  2. 검색 <artifactId>maven-surefire-plugin</artifactId>
  3. <configuration>요소를 추가 한 다음 아래에 표시된 것처럼 <argLine>하위 요소를 추가하십시오.-Xmx512m -XX:MaxPermSize=256m

<configuration> <argLine>-Xmx512m -XX:MaxPermSize=256m</argLine> </configuration>

그것이 도움이되기를 바랍니다, 행복한 프로그래밍 :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.