[JVM 심층 이해]: OutOfMemoryError 이상 요약
Sun의 HotSpot 가상 머신을 기반으로 Eclipse에서 Run/Arguments에서 가상 머신 시작 매개 변수를 설정할 수 있습니다. 이 매개 변수는 실험 결과에 직접적인 영향을 미치므로 무시할 수 없습니다.
Java 더미 오버플로우
Java 더미는 대상을 저장하는 실례에 사용됩니다. 대상을 끊임없이 만들고 GC Roots에서 대상 사이에 도달할 수 있는 경로를 확보하여 쓰레기 회수 메커니즘이 이 대상을 제거하는 것을 피하고 대상 수량이 최대 더미 용량 제한에 도달하면 넘침이 발생합니다.
Java 스택의 크기를 20MB로 제한하고 최소값과 최대값이 같다(확장 불가).가상 머신에 메모리 넘침 이상이 발생했을 때 Dump는 사후 분석을 위해 현재 메모리 덤프 스냅샷을 내보냅니다.
package com.jvm.OutOfMemoryError;
import java.util.List;
import java.util.ArrayList;
/** * Java * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError */
public class HeapOOM {
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while(true) {
// list , Full GC
list.add(new OOMObject());
}
}
static class OOMObject {
}
}
실행 결과:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid7768.hprof ...
Heap dump file created [27987840 bytes in 0.142 secs]
이런 이상은 비교적 흔히 볼 수 있다. 일반적으로 메모리 이미지 분석 도구(예를 들어 Eclipse Memory Analyzer)를 통해 Dump에서 나온 덤프 메모리 스냅 사진을 분석하는데 메모리 유출인지 메모리 넘침인지 확인한다.
가상 머신 및 로컬 메소드 스택 오버플로우
HotSpot은 가상 머신 스택과 로컬 메소드 스택을 구분하지 않으며 스택 용량은 -Xss 매개 변수로만 설정할 수 있습니다.
package com.jvm.OutOfMemoryError;
/** * StackOverFlow * VM Args:-Xss128k */
public class JavaVMStackSOF {
private int stackLength = 1;
// , ,
public void stackLeak() {
stackLength++;
stackLeak();
}
public static void main(String[] args) {
JavaVMStackSOF oom = new JavaVMStackSOF();
try {
oom.stackLeak();
} catch (Throwable e) {
System.out.println("stack length: " + oom.stackLength);
throw e;
}
}
}
실행 결과:
stack length: 999
Exception in thread "main" java.lang.StackOverflowError
at com.jvm.OutOfMemoryError.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:26)
at com.jvm.OutOfMemoryError.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:26)
at com.jvm.OutOfMemoryError.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:26)
......
OutOfMemoryError: 스택 공간이 충분한지 여부에 관계없이 멀티스레드에서 메모리가 넘칩니다.모든 스레드의 창고에 할당된 메모리가 클수록 (매개 변수 - Xss) 구축할 수 있는 스레드의 수량이 적고, 스레드를 구축할 때 남은 메모리를 소모하기 쉬우며, 메모리가 넘치기 쉽다.이 경우 스레드 수를 줄이지 못하거나 64비트 가상 머신을 교체할 때 가장 많은 스택 용량을 줄이고 스택 용량을 줄이면 더 많은 스레드를 교체할 수 있다.
주의: Windows 플랫폼 가상기에서 자바의 스레드는 운영체제의 내부 스레드에 비추어 실행되며, 아래의 코드 실행은 시스템의 가사를 초래할 수 있습니다!
package com.jvm.OutOfMemoryError;
/** * * * !!!!! !!!!! * !!!! * * VM Args:-Xss2M( ) */
public class JavaVMStackOOM {
private void dontStop() {
while(true) {
}
}
// OutOfMemoryError
public void stackLeakByThread() {
while(true) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) {
JavaVMStackOOM oom = new JavaVMStackOOM();
oom.stackLeakByThread();
}
}
방법 영역과 운행 상수 탱크 넘침
운행 시간 탱크
JDK1.7 점차적으로'영구대'를 걷기 시작하는데 아래의 토론은 실제 영향을 시험할 수 있다.
String.()는 이 String 대상의 내용과 같은 문자열이 실행 중인 경우 상수 탱크에 있는 문자열의 인용을 되돌려주는 Native 방법입니다.없으면 이 String 내용과 같은 문자열을 상수 풀에 만들고 상수 풀에서 만든 문자열의 인용을 되돌려줍니다.JDK7의 인터넷 () 방법은 상량 탱크에 이 문자열이 없을 때 상량 탱크에서 이 String 내용과 같은 문자열을 만드는 것이 아니라 상량 탱크에 기록된 더미에서 처음 나타나는 이 문자열의 인용으로 바꾸어 이 인용을 되돌려줍니다.
JDK에서 1.6 이전에 상수 풀은 영구 세대에 분배되었고 다음 코드는 JDK1.6에서 실행하고 나서야 메모리 오버플로우가 발생합니다. JDK1.7 및 그 다음 버전이 실행되면 사순환이 발생합니다.
package com.jvm.OutOfMemoryError;
import java.util.ArrayList;
import java.util.List;
/** * * * jdk1.7 “ ”,jdk1.6 * -XX:PermSize=10M -XX:MaxPermSize=10M ( ) */
public class RuntimeConstantPoolOOM {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
int i = 0;
while(true) {
// list , Full GC
list.add(String.valueOf(i++).intern());
}
}
}
실행 결과:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
......
방법구
방법구는Class와 관련된 정보를 저장하는 데 사용되며, 실행할 때 대량의 클래스가 방법구를 채우면 방법구의 메모리가 넘칠 수 있습니다.예를 들어 주류 프레임워크인 Spring,Hibernate가 대량의 클래스를 강화할 때 CGLib 바이트 코드를 이용하여 동적 클래스를 생성한다.대량의 JSP 또는 동적 JSP(JSP가 처음 실행될 때 Java 클래스로 컴파일되어야 함).
다음은 CGLib 동적 생성 클래스로 인한 메소드 오버플로우입니다.
package com.jvm.OutOfMemoryError;
import java.lang.reflect.Method;
import com.jvm.OutOfMemoryError.HeapOOM.OOMObject;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/** * * -XX:PermSize=10M -XX:MaxPermSize=10M */
public class JavaMethodAreaOOM {
public static void main(String[] args) {
while(true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method m, Object[] objs, MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
return proxy.invokeSuper(obj, objs);
}
});
enhancer.create();
}
}
}
실행 결과:
Caused by: java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
......
로컬 직접 메모리 오버플로우
자바 가상기는 파라미터-XX:MaxDirectMemorySize를 통해 이 컴퓨터의 직접 메모리 사용 가능한 크기를 설정할 수 있으며, 지정하지 않으면 기본적으로 자바 더미 메모리 크기와 같습니다.JDK에서 반사로 Unsafe 클래스를 가져올 수 있습니다. (Unsafe의 getUnsafe () 방법은 클래스 마운트기 Bootstrap을 시작해야만 실례를 되돌릴 수 있습니다.) 이 컴퓨터의 직접 메모리를 조작할 수 있습니다.-XX:MaxDirectMemorySize=10M을 사용하여 최대 사용 가능한 네이티브 메모리 크기를 10MB로 제한합니다.
import java.lang.reflect.Field;
public class DirectMemoryOOM {
private static final int _1MB = 1024 * 1024 * 1024;
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe . class .getDeclaredFields()[0];
unsafeField.setAccessible( true );
Unsafe unsafe = ( Unsafe ) unsafeField.get( null );
while ( true ) {
// unsafe
unsafe.allocateMemory( _1MB );
}
}
}
실행 결과:
Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
......
이러한 예외의 뚜렷한 특징은 Heap Dump 파일에서 뚜렷한 예외가 보이지 않는다는 것입니다.만약 OOM 이후 Dump의 파일이 비교적 작고 프로그램에서 IO/NIO를 직접 또는 간접적으로 사용했다면 이 방면의 원인을 고려할 수 있다.
1. 주지명을 참고하여 자바 가상기기: JVM의 고급 특성과 최상의 실천, 기계공업출판사
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
자바 문자열 풀우리는 Java에서 문자열이 힙 메모리 영역에 저장된다는 것을 알고 있습니다. 이 힙 메모리 내부에는 String Pool이라는 특정 메모리 영역이 있습니다. 문자열 프리미티브를 생성하면 자바 문자열의 불변성 덕분에...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.