Java Virtual Machine Specification은 JVM 메모리가 힙, 스택, 프로그램 카운터, 메소드 영역 등과 같은 여러 블록으로 나뉘어져 있음을 규정합니다. 핫스팟 JVM 구현에서 힙 메모리는 세 가지 부분, 새로운 세대, 노년 및 지속적인 대역으로 나뉩니다. 영구 대역은 사양에 지정된 방법 영역을 구현하고 메모리 모델의 다른 부분에는 해당하는 OutofMemoryError 오류가 있습니다. 다음으로 별도로 논의 해 봅시다. 나는 대부분의 개발자 가이 오류를 발견했다고 생각하며,이 오류의 이유는 주로 다음과 같은 이유로 인해 발생합니다.
JVM 메모리가 너무 작고 프로그램이 빡빡하지 않아서 쓰레기가 너무 많습니다.
OutofMemoryError 예외의 몇 가지 일반적인 원인이 있습니다.
이 오류에 대한 일반적인 오류 프롬프트 :
stackoverflowerror
오버플로 스택은 java.lang.stackoverflowerror 오류를 던졌습니다. 스택의 깊이가 메소드가 실행될 때 가상 시스템에서 허용되는 최대 깊이를 초과하기 때문에 발생합니다. 이 상황은 일반적으로 프로그램 오류로 인해 발생합니다. 예를 들어, 죽은 재귀를 쓰면 이러한 상황이 발생할 수 있습니다. 코드를 통해이 상황에서 메모리 오버 플로우를 시뮬레이션하겠습니다.
java.util.*; java.lang.*; public class oomtest {public void stackoverflowmethod () {stackoverflowmethod (); } public static void main (String ... args) {Oomtest oom = new Oomtest (); oom.stackoverflowmethod (); }} 위의 코드를 실행하면 다음과 같은 예외가 발생합니다.
스레드의 예외 "main"java.lang.stackoverflowerror at oomtest.stackoverflowmethod (oomtest.java:6)
힙 오버 플로우 (OutofMemoryError : Java 힙 스페이스)
힙 메모리가 넘치면 가상 머신은 java.lang.outofmemoryerRor : java 힙 스페이스를 던졌습니다. 이 경우 메모리가 오버플로 될 때 생성 된 덤프 파일을 기반으로 특별히 분석해야합니다 (-xx : +heapDumponOutofMemoryErrorJVM 시작 매개 변수를 추가해야 함). 이러한 문제가 발생하면 메모리 누출 또는 메모리 오버플 로일 수 있습니다.
메모리가 누출되면 누출 된 물체가 GC 루트로 어떻게 참조되는지 확인한 다음 기준 체인을 통해 누출의 원인을 분석해야합니다.
메모리 오버플로 문제가있는 경우 프로그램이 가상 머신에 대해 구성하는 메모리보다 더 많은 메모리가 필요하기 때문입니다. 이 경우 -xmx를 사용 하여이 문제를 해결할 수 있습니다.
아래에서 우리는 다음 코드를 통해이 상황의 오버플로를 보여줍니다.
java.util.*; java.lang.*; public class oomtest {public static void main (String ... args) {list <byte []> buffer = new arraylist <byte []> (); buffer.add (새로운 바이트 [10*1024*1024]); }} 다음 명령을 통해 위의 코드를 실행합니다.
java -verbose : gc -xmn10m -xms20m -xmx20m -xx :+printgc oomtest
이 프로그램은 다음 정보를 입력합니다.
[GC 1180K-> 366K (19456K), 0.0037311 SECS] [전체 GC 366K-> 330K (19456K), 0.0098740 SECS] [전체 GC 330K-> 292K (19456K), 0.0090244 SECS] 스레드 "메인"JAVA.LANG.LANG.LANG. oomtest.main (oomtest.java:7)
실행 결과에서 JVM이 작은 GC를 한 번, 주요 GC를 두 번 수행했음을 알 수 있습니다. 주요 GC의 출력에서 GC 이후의 이전 영역의 사용률은 134K이고 바이트 어레이는 10m이므로 구식 공간보다 더 크게 추가되므로 예외가 발생합니다. -xms21m 및 -xmx21m이 조정되면 GC 작업이 트리거되지 않으며 예외는 없습니다.
위의 실험을 통해, 결론이 측면에서 확인되었습니다. 물체가 새로운 세대의 나머지 기억보다 클 때, 그것은 노년기 직접 배치됩니다. 노년의 나머지 기억을 여전히 내려 놓을 수 없으면 쓰레기 수집이 유발됩니다. 수집 후에도 여전히 내려갈 수없는 경우 메모리 오버플로 예외가 발생합니다.
페름기 공간
Hotspot JVM은 영구 대역을 통해 Java 가상 머신 사양의 메소드 영역을 구현하며 런타임 상수 풀은 방법 영역에 저장됩니다. 따라서 지속적인 밴드 오버플로는 런타임 상수 풀 오버 플로우 일 수 있거나 메소드 영역에 저장된 클래스 객체가 제 시간에 재활용되지 않거나 클래스 정보가 차지하는 메모리가 구성을 초과합니다. 지속성 밴드가 넘치면 java.lang.outofmemoryerror : permgen 공간이 던져집니다.
작업 할 때 다음 시나리오 에서이 문제를 경험할 수 있습니다.
일부 애플리케이션 서버의 핫 배포를 사용할 때는 여러 번 핫 배포를 만나고 메모리가 오버플로 나타납니다. 이는 각 핫 배치 후 원래 클래스가 제거되지 않았기 때문입니다.
응용 프로그램 자체가 더 크고 더 많은 클래스 라이브러리가 포함 된 경우,이 문제는 영구 대역에 할당하는 메모리 (-xx : permsize 및 -xx : maxpermsize)가 비교적 작을 때 발생할 수 있습니다.
Spring 및 Hibernate와 같은 일부 타사 프레임 워크는 모두 CGLIB와 같은 바이트 코드 생성 기술 (예 : 동적 생성 클래스 파일을 저장하기 위해 더 큰 방법 영역이 필요할 수있는 일부 향상된 기능을 구현합니다.
우리는 자바의 줄 상수가 일정한 풀에 배치된다는 것을 알고 있습니다. String.intern () 메소드가 실행되면이 문자열과 동일한 객체가 상수 풀에 저장되어 있는지 확인합니다. 존재하는 경우 상수 풀의 물체에 대한 참조를 직접 반환하십시오. 존재하지 않으면이 문자열을 먼저 상수 풀에 추가 한 다음 문자열에 대한 참조를 반환하십시오. 그런 다음 String.intern 메소드를 통해 런타임 동안 상수 영역의 오버플로를 시뮬레이션 할 수 있습니다. 다음 코드를 통해이 상황을 시뮬레이션하겠습니다.
java.util.*; java.lang.*; public class oomtest {public static void main (String ... args) {list <string> list = new arraylist <string> (); while (true) {list.add (uuid.randomuuid (). toString (). 인턴 ()); }}}다음 명령을 통해 위의 코드를 실행합니다.
java -verbose : gc -xmn5m -xms10m -xmx10m -xx : maxpermsize = 1m -xx :+printgc oomtest
실행 후 입력은 아래 그림에 나와 있습니다.
스레드의 예외 "main"java.lang.outofMemoryError : java.lang.string.intern (기본 메소드)의 permgen space (oomtest.main) (oomtest.java:8)
위의 코드를 통해 런타임 동안 상수 풀 오버플로를 성공적으로 시뮬레이션했습니다. 출력의 Permgen 공간에서, 우리는 영구 밴드가 실제로 넘쳐나는 것을 알 수 있으며, 이는 핫스팟 JVM이 앞에서 언급 한 것처럼 영구 대역을 통해 방법 영역을 구현한다는 진술을 확인합니다.
OutofMemoryError : 기본 스레드를 만들 수 없습니다
마지막으로, 오류 java.lang.outofmemoryerRor : natvie 스레드를 만들 수 없음을 살펴 보겠습니다. 이런 일이 발생하면 일반적으로 다음 두 가지 상황으로 인해 발생합니다.
프로그램에서 생성 된 스레드 수는 운영 체제 제한을 초과합니다. Linux 시스템의 경우 Ulimit -u를 통해이 제한을 볼 수 있습니다.
가상 머신에 할당 된 메모리가 너무 커서 스레드를 만들 때 필요한 기본 메모리가 너무 적습니다. 우리는 모두 운영 체제가 각 프로세스의 메모리에 한계가 있다는 것을 알고 있습니다. JVM을 시작할 때 프로세스를 시작하는 것과 같습니다. 당사 프로세스 중 하나가 4G의 메모리를 차지하는 경우 다음 공식을 통해 계산 된 나머지 메모리는 스레드 스택을 구축 할 때 사용할 수있는 메모리입니다. 스레드 스택에 사용 가능한 총 메모리 = 4g- (-xmx)-(-xx : maxpermsize의 값)-프로그램 카운터가 차지하는 메모리는 -xmx 및 maxpermsize의 값이 클수록 스레드 스택에 사용 가능한 공간이 작다는 위의 공식으로 표시됩니다. -XSS 매개 변수로 구성된 스택 용량이 변경되지 않은 상태로 유지되면 생성 할 수있는 스레드 수가 적을 수 있습니다. 따라서이 상황으로 인해 기본 스레드를 생성 할 수없는 경우 프로세스가 차지하는 총 메모리를 증가 시키거나 더 많은 스레드를 생성하는 목적을 달성하기 위해 -xmx 또는 -xss를 줄입니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.