자바 메모리 넘 침 실현 원인 및 솔 루 션

1.JVM 힙(더미)넘 침:java.lang.OutOfmoryError:Java heap space
JVM 은 시작 할 때 JVM Heap 의 값 을 자동 으로 설정 하 며,JVM 이 제공 하 는-Xmn-Xms-Xmx 등의 옵션 을 이용 하여 설정 할 수 있 습 니 다.힙 의 크기 는 Young Generation 과 Tenured Generaion 의 합 이다.JVM 에서 98%의 시간 이 GC 에 사용 되 고 사용 가능 한 Heap size 가 2%미 만인 경우 이 이상 정 보 를 던 집 니 다.
해결 방법:JVM Heap(더미)의 크기 를 수 동 으로 설정 합 니 다.
자바 더 미 는 대상 인 스 턴 스 를 저장 하 는 데 사 용 됩 니 다.대상 인 스 턴 스 를 위해 메모 리 를 할당 해 야 할 때,쌓 인 메모리 사용량 은-Xmx 설정 의 최대 값 에 이 르 렀 습 니 다.OutOf Memory Error 이상 을 던 집 니 다.예 는 다음 과 같다.

package com.demo.test;

import java.util.ArrayList;
import java.util.List;

/**
 * VM Args: -Xms5m -Xmx5m
 */
public class HeapOOM {
  
  public static void main(String[] args) {
    int count = 0;
    List<Object> list = new ArrayList<Object>();
    while(true){
      list.add(new Object());
      System.out.println(++count);
    }
  }

}
그리고 실행 할 때 jvm 인 자 를 설정 합 니 다.다음 과 같 습 니 다.

-Xmx 는 5m.그 중 한 번 의 테스트 결 과 는 count 의 값 이 360145 까지 누적 되면 다음 과 같은 이상 이 발생 합 니 다.
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2245) at java.util.Arrays.copyOf(Arrays.java:2219) at java.util.ArrayList.grow(ArrayList.java:213) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:187) at java.util.ArrayList.add(ArrayList.java:411) at com.demo.test.HeapOOM.main(HeapOOM.java:12)
수정-Xmx 10m.이 중 한 번 의 테스트 결 과 는 count 의 값 이 540217 까지 누적 되 었 을 때 OutOf Memory Error 이상 이 발생 한 것 으로 나 타 났 다.-Xmx 매개 변수 값 이 커지 면서 자바 더미 에 저장 할 수 있 는 대상 도 많 습 니 다.
2.PermGen space 넘 침:java.lang.OutOfmoryError:PermGen space
PermGen space 의 전 칭 은 Permanent Generation space 로 메모리 의 영구 저장 영역 을 말한다.메모리 가 넘 치 는 이 유 는 JVM 이 주로 Class 와 Meta 정 보 를 저장 하기 때 문 입 니 다.Class 는 Load 될 때 PermGen space 영역 에 들 어 갑 니 다.Instance 를 저장 하 는 Heap 영역 과 달리 sun 의 GC 는 주 프로그램 실행 기간 에 PermGen space 를 정리 하지 않 기 때문에 앱 이 CLASS 를 많이 불 러 옵 니 다.PermGen space 가 넘 칠 수 있 습 니 다.일반적으로 프로그램의 시작 단계 에서 발생 한다.
해결 방법:-XX:PermSize 와-XX:MaxPermSize 를 통 해 영구 세대 크기 를 설정 하면 됩 니 다.
방법 구역 은 자바 형식의 관련 정 보 를 저장 하 는 데 사 용 됩 니 다.예 를 들 어 클래스 이름,방문 수정자,상수 탱크,필드 설명,방법 설명 등 입 니 다.클래스 로 더 가 class 파일 을 메모리 에 불 러 오 는 과정 에서 가상 기 회 는 그 중의 유형 정 보 를 추출 하고 이 정 보 를 방법 구역 에 저장 합 니 다.클래스 정 보 를 저장 해 야 하고 방법 구역 의 메모리 사용량 이-XX:MaxPermSize 설정 의 최대 값 에 이 르 렀 을 때 OutOfmory Error 이상 을 던 집 니 다.이런 상황 에 대한 테스트 에 있어 기본 적 인 사 고 는 운행 할 때 대량의 유형 이 방법 구역 을 채 우 고 넘 칠 때 까지 하 는 것 이다.CGLib 를 통 해 바이트 코드 를 직접 조작 해 야 할 때 대량의 동적 클래스 가 생 성 되 었 습 니 다.예 는 다음 과 같다.

package com.demo.test;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.MethodInterceptor;

/**
 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class MethodAreaOOM {

  public static void main(String[] args) {
    int count = 0;
    while (true) {
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(MethodAreaOOM.class);
      enhancer.setUseCache(false);
      enhancer.setCallback(new MethodInterceptor() {
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
          return proxy.invoke(obj, args);
        }
      });
      enhancer.create();
      System.out.println(++count);
    }
  }

}
-XX:MaxPerm Size 는 10m 입 니 다.그 중 한 번 의 테스트 결 과 는 count 의 값 이 800 까지 누적 되면 다음 과 같은 이상 이 발생 합 니 다.
Caused by: java.lang.OutOfMemoryError: PermGen space at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:792) ... 8 more
-XX:MaxPermSize 매개 변수 값 이 커지 면서 자바 방법 구역 에 저장 할 수 있 는 형식 데이터 도 많 습 니 다.
3.스 택 넘 침:java.lang.StackOverflow 오류:Thread Stack space
스 택 이 넘 쳤 습 니 다.JVM 은 여전히 스 택 식 가상 머 신 을 사용 합 니 다.이것 은 C 와 Pascal 과 같 습 니 다.함수 의 호출 과정 은 모두 창고 와 창고 에서 나 타 났 다.구조 함 수 를 호출 하 는'층'이 너무 많아 서 스 택 구역 이 넘 쳤 습 니 다.일반적으로 일반 스 택 구역 은 쌓 인 구역 보다 훨씬 작 습 니 다.함수 호출 과정 이 수천 층 보다 많 지 않 기 때문에 모든 함수 호출 에 1K 의 공간 이 필요 하 더 라 도(이것 은 한 C 함수 에서 256 개의 int 형식의 변 수 를 설명 하 는 것 과 같 습 니 다)스 택 구역 은 1MB 의 공간 이 필요 합 니 다.보통 창고 의 크기 는 1-2MB 이다.쉽게 말 하면 단일 스 레 드 프로그램 에 필요 한 메모리 가 너무 크다 는 것 이다.일반적으로 재 귀적 으로 도 재 귀적 인 차원 이 너무 많 으 면 넘 치기 쉽다.
해결 방법:1:프로그램 수정.2:-Xss:를 통 해 각 스 레 드 의 Stack 크기 를 설정 하면 됩 니 다.
자바 가상 컴퓨터 규범 에서 이 지역 에 대해 두 가지 이상 상황 을 규정 했다.StackOverflow Error 와 OutOf Memory Error 이상 이다.
(1)StackOverflow 오류 이상
자바 프로그램 코드 가 새 스 레 드 를 시작 할 때마다 자바 가상 머 신 은 자바 스 택 을 할당 합 니 다.자바 스 택 은 프레임 단위 로 스 레 드 의 운행 상 태 를 저장 합 니 다.스 레 드 가 자바 방법 을 호출 할 때 가상 머 신 은 이 스 레 드 의 자바 스 택 에 새 스 택 프레임 을 누 릅 니 다.이 방법 이 아직 돌아 오지 않 았 다 면 그것 은 줄곧 존재 할 것 이다.
만약 에 스 레 드 방법 이 플러그 인 호출 차원 이 너무 많 으 면(예 를 들 어 재 귀적 호출)자바 스 택 의 프레임 이 점점 증가 함 에 따라 최종 적 으로 이 스 레 드 자바 스 택 의 모든 스 택 프레임 크기 가-Xss 설정 값 보다 크 기 때문에 StackOverflow Error 메모리 에 이상 이 생 길 수 있 습 니 다.예 는 다음 과 같다.

package com.demo.test;
/**
 * VM Args: -Xss128k
 */
public class JavaVMStackSOF {
  private int count = 0;
  public static void main(String[] args) {
    new JavaVMStackSOF().method();
  }  
  public void method() {
    System.out.println(++count);
    method();
  }
}
-Xss 는 128 k.그 중 한 번 의 테스트 결 과 는 count 의 값 이 2230 까지 누적 되면 다음 과 같은 이상 이 발생 합 니 다.
Exception in thread "main" java.lang.StackOverflowError at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77) at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:564) at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:619) at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:561) at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271) at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125) at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207) at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129) at java.io.PrintStream.write(PrintStream.java:526) at java.io.PrintStream.print(PrintStream.java:597) at java.io.PrintStream.println(PrintStream.java:736) at com.demo.test.JavaVMStackSOF.method(JavaVMStackSOF.java:15)
-Xss 매개 변수 값 이 커지 면서 끼 워 넣 을 수 있 는 방법 호출 차원 도 상응 하 게 증가 합 니 다.다시 말하자면 StackOverflow Error 이상 은 방법 호출 의 차원 이 너무 깊 어서 최종 적 으로 특정한 스 레 드 에 분 배 된 모든 스 택 프레임 의 크기 가-Xss 설정 의 값 보다 커서 StackOverflow Error 이상 이 발생 한 것 이다.
(2)OutOfmory 오류 이상
자바 프로그램 코드 가 새 스 레 드 를 시작 할 때 이 스 레 드 에 자바 스 택 을 할당 할 충분 한 메모리 공간 이 없습니다.예 는 다음 과 같다.

package com.demo.test;

/**
 * VM Args: -Xss128k
 */
public class JavaVMStackOOM {

  public static void main(String[] args) {
    int count = 0;
    while (true) {
      Thread thread = new Thread(new Runnable() {
        public void run() {
          while (true) {
            try {
              Thread.sleep(5000);
            } catch (Exception e) {
            }
          }
        }
      });
      thread.start();
      System.out.println(++count);
    }
  }

}
-Xss 는 128 k.그 중 한 번 의 테스트 결 과 는 count 의 값 이 11958 까지 누적 되면 다음 과 같은 이상 이 발생 합 니 다.
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:693)
at com.demo.test.JavaVMStackOOM.main(JavaVMStackOOM.java:21)
-Xss 매개 변수 값 이 커지 면서 자바 프로그램 이 만 들 수 있 는 버스 프로 세 스 가 적 습 니 다.
4.그래서 서버 용기 가 시 작 될 때 우 리 는 항상 JVM 의 몇 가지 인 자 를 다음 과 같이 관심 을 가지 고 설정 합 니 다.
  • -Xms:자바 힙 의 초기 크기,기본 값 은 물리 메모리 의 1/64 입 니 다
  • -Xmx:자바 힙 최대 치,물리 적 메모 리 를 초과 할 수 없습니다
  • -Xmn:young generation 의 힙 크기 는 보통 Xmx 의 3,4 분 의 1 로 설정 합 니 다.젊 은 세대 가 커지 면 나이 든 세대 의 크기 가 줄 어 들 고 감시 에 따라 합 리 적 으로 설정 할 수 있다
  • -Xss:모든 스 레 드 의 Stack 크기 이 고 가장 좋 은 값 은 128 K 이 어야 합 니 다.기본 값 은 512 k 인 것 같 습 니 다
  • -XX:PermSize:메모리 의 영구 저장 구역 의 초기 크기 를 설정 하고 부족 한 값 은 64M 입 니 다
  • -XX:MaxPermSize:메모리 의 영구 저장 영역 최대 크기 를 설정 하고 부족 한 값 은 64M 입 니 다
  • -XX:Survivor Ratio:Eden 구역 과 Survivor 구역 의 크기 비례 는 8 로 설정 하면 두 개의 Survivor 구역 과 한 Eden 구역 의 비례 는 2:8 이 고 한 개의 Survivor 구역 은 전체 젊 은 세대 의 1/10 을 차지한다
  • -XX:+UseParallelGC:F 젊 은 세 대 는 동시 수집 을 사용 하고 늙 은 세 대 는 직렬 수집 을 사용 합 니 다
  • -XX:+UseParNewGC:젊 은 세 대 를 병행 수집 으로 설정 합 니 다.JDK 5.0 이상,JVM 은 시스템 설정 에 따라 자체 적 으로 설정 합 니 다.이 값 을 다시 설정 할 필요 가 없습니다
  • -XX:ParallelGCthreads:병렬 수집 기의 스 레 드 수,값 은 프로세서 수 와 동일 하 게 CMS 에 적용 하 는 것 이 좋 습 니 다
  • -XX:+UseParallelOldGC:연대 쓰레기 수집 방식 은 병행 수집(Parallel Compacting)입 니 다
  • -XX:MaxGCpause Millis:젊 은 세대 의 쓰레기 를 회수 하 는 데 가장 긴 시간(최대 일시 정지 시간)이 걸 리 지 않 으 면 JVM 은 젊 은 세대 의 크기 를 자동 으로 조정 하여 이 값 을 만족 시 킵 니 다
  • -XX:+Scavenge BeforeFullGC:Full GC 앞에서 YGC 를 호출 합 니 다.기본 값 은 true 입 니 다
  • 인 스 턴 스:JAVAOPTS=”-Xms4g -Xmx4g -Xmn1024m -XX:PermSize=320M -XX:MaxPermSize=320m -XX:SurvivorRatio=6″
    첫 번 째 OutOf Memory Error:PermGen space
    이러한 문제 가 발생 한 원 의 는 프로그램 에서 대량의 jar 나 class 를 사용 하여 자바 가상 컴퓨터 로 딩 류 의 공간 이 부족 하고 Permanent Generation space 와 관련 이 있다 는 것 이다.이런 문 제 를 해결 하 는 데 는 다음 과 같은 두 가지 방법 이 있다.
    1.자바 가상 컴퓨터 의 XX:PermSize 와 XX:MaxPermSize 매개 변수의 크기 를 증가 합 니 다.그 중에서 XX:PermSize 는 초기 영구 저장 영역 크기 이 고 XX:MaxPermSize 는 최대 영구 저장 영역 크기 입 니 다.tomcat 6.0 을 대상 으로 catalina.sh 또는 catalina.bat 파일 에서 일련의 환경 변수 이름 설명 끝 부분(약 70 줄 정도)에 한 줄 추가:JAVAOPTS='-XX:PermSize=64M-XX:MaxPermSize=128 m'윈도 우즈 서버 라면 시스템 환경 변수 에 도 설정 할 수 있다.tomcat 로 sprint+struts+hibenate 구 조 를 발표 할 때 이러한 메모리 넘 침 오류 가 발생 하기 쉽다 고 생각 합 니 다.상기 방법 을 사용 하여 저 는 ssh 프로젝트 를 배치 하 는 tomcat 서버 가 자주 지연 되 는 문 제 를 성공 적 으로 해결 하 였 습 니 다.
    2.응용 프로그램 에서 웹-inf/lib 의 jar 를 청소 합 니 다.만약 에 tomcat 에 여러 개의 응용 프로그램 을 배치 하면 많은 응용 프로그램 이 같은 jar 를 사용 합 니 다.공 통 된 jar 를 tomcat 의 공 통 된 lib 로 옮 겨 서 클래스 의 중복 로드 를 줄 일 수 있 습 니 다.이런 방법 은 인터넷 에서 일부 사람들 이 추천 한 것 이다.나 는 해 본 적 이 없 지만 큰 공간 을 줄 일 수 없다 고 느낀다.가장 믿 을 만 한 것 은 역시 첫 번 째 방법 이다.
    두 번 째 OutOfmoryError:Java heap space
    이러한 문제 가 발생 한 이 유 는 자바 가상 컴퓨터 가 만 든 대상 이 너무 많 기 때 문 입 니 다.쓰레기 수 거 를 하 는 동안 가상 컴퓨터 가 분 배 된 메모리 공간 이 이미 꽉 찼 기 때 문 입 니 다.Heap space 와 관련 이 있 습 니 다.이런 문 제 를 해결 하 는 데 는 두 가지 사고방식 이 있다.
    1.프로그램 을 검사 하고 순환 이 없 거나 불필요 하 게 대량의 대상 을 만 드 는 지 확인 합 니 다.원인 을 찾 은 후 프로그램 과 알고리즘 을 수정 합 니 다.제 가 예전 에 K-Means 텍스트 클 러 스 터 알고리즘 을 사용 하여 몇 만 개의 텍스트 기록(각 기록 의 특징 벡터 는 약 10 개)을 텍스트 클 러 스 터 로 만 들 었 을 때 프로그램의 디 테 일 에 문제 가 있어 자바 힙 스페이스 의 메모리 넘 침 문 제 를 초래 했 고 나중에 수정 프로그램 을 통 해 해결 되 었 습 니 다.
    2.자바 가상 컴퓨터 에서 Xms(초기 더미 크기)와 Xmx(최대 더미 크기)매개 변수의 크기 를 증가 합 니 다.set JAVAOPTS= -Xms256m -Xmx1024m
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기