면접관: 온라인에서 OOM을 접하게 된다면 어떻게 해결하나요?
OOM은 개발자들이 가장 두려워하는 문제 중 하나라고 할 수 있으며, 그 원인은 기본적으로 코드나 JVM 매개변수 구성에 의해 발생합니다.
이 기사에서는 Java 프로세스가 OOM을 트리거한 후 문제를 해결하는 방법에 대해 독자에게 설명합니다.
제작 환경에 대한 경외심이 많다고 하는데, 문제를 빠르게 해결하는 것도 경외감의 표시입니다

OOM
OOM은 "Out Of Memory"를 뜻하는 "Out Of Memory"의 약자입니다. 메모리가 소진되었음을 의미합니다. JVM에 객체에 할당할 공간이 부족하고 가비지 수집기에 재활용할 공간이 없으면 이 오류가 발생합니다
OOM이 발생하는 이유는 일반적으로 이러한 문제 때문입니다
너무 적습니다. 할당 : JVM 초기화 메모리가 적고, 업무상 메모리를 많이 사용하거나, JVM 영역별로 메모리 할당이 무리하다 코드 취약점: 특정 객체를 자주 신청하지만 해제하지 않는다. 더 이상 사용되지 않아 메모리 소진이 발생합니다
메모리 누수: 적용한 메모리가 해제되지 않아 가상 머신에서 해당 메모리를 다시 사용할 수 없게 됩니다. 이때 이 메모리가 누수됩니다. . 신청자는 더 이상 사용하지 않지만 가상머신을 다른 사람에게 할당할 수 없기 때문입니다.
메모리 오버플로: 적용된 메모리가 JVM이 제공할 수 있는 메모리 크기를 초과하는 경우를 오버플로라고 합니다.
메모리 누수가 계속되고 결국에는 오버플로되어야 합니다. 둘은 인과적으로 관련되어 있습니다.Common OOM
더 일반적인 OOM 유형은 다음과 같습니다java.lang.OutOfMemoryError: PermGen space
Java7 영구 생성(메서드 영역) 오버플로, 클래스 정보, 상수, 정적 변수, JIT(Just-In-Time) 컴파일러로 컴파일된 코드 등 가상 머신에서 로드한 데이터를 저장하는 데 사용됩니다. 클래스가 처음 로드될 때마다 메타데이터는 영구 생성에 저장됩니다일반적으로 다수의 클래스 객체 또는 JSP 페이지에 나타나거나 CgLib 동적 프록시 기술을 사용하여 나타납니다
-XX: PermSize
및 -XX:MaxPermSize
메소드 영역의 크기 수정-XX:PermSize
和 -XX:MaxPermSize
修改方法区大小
Java8 将永久代变更为元空间,报错:java.lang.OutOfMemoryError: Metadata space,元空间内存不足默认进行动态扩展
java.lang.StackOverflowError
虚拟机栈溢出,一般是由于程序中存在 死循环或者深度递归调用 造成的。如果栈大小设置过小也会出现溢出,可以通过 -Xss
设置栈的大小
虚拟机抛出栈溢出错误,可以在日志中定位到错误的类、方法
java.lang.OutOfMemoryError: Java heap space
Java 堆内存溢出,溢出的原因一般由于 JVM 堆内存设置不合理或者内存泄漏导致
如果是内存泄漏,可以通过工具查看泄漏对象到 GC Roots 的引用链。掌握了泄漏对象的类型信息以及 GC Roots 引用链信息,就可以精准地定位出泄漏代码的位置
如果不存在内存泄漏,就是内存中的对象确实都还必须存活着,那就应该检查虚拟机的堆参数(-Xmx 与 -Xms),查看是否可以将虚拟机的内存调大些
小结:方法区和虚拟机栈的溢出场景不在本篇过多讨论,下面主要讲解常见的 Java 堆空间的 OOM 排查思路
查看 JVM 内存分布
假设我们 Java 应用 PID 为 15162,输入命令查看 JVM 内存分布 jmap -heap 15162
Java8은 영구 생성을 메타스페이스로 변경하고 오류가 보고됩니다: java.lang.OutOfMemoryError: Metadata space. 메모리가 부족하고 기본적으로 동적으로 확장됩니다
java.lang.StackOverflowError
🎜가상 머신 스택 오버플로, 일반적으로 infinite의 존재로 인해 발생 프로그램에서 루프 또는 심층 재귀 호출이 발생했습니다. 스택 크기를 너무 작게 설정하면 오버플로가 발생합니다.-Xss
스택 크기 설정 🎜🎜가상 머신에서 스택 오버플로 오류가 발생합니다. 로그🎜🎜java에서 잘못된 클래스와 메소드를 찾을 수 있습니다. lang.OutOfMemoryError: Java 힙 공간🎜🎜Java 힙 메모리 오버플로, 오버플로는 일반적으로 불합리한 JVM 힙 메모리 설정 또는 메모리 누수로 인해 발생합니다.🎜🎜메모리 누수인 경우 다음을 수행할 수 있습니다. 도구를 사용하여 GC Roots의 참조 체인을 확인하세요. 유출된 객체의 타입 정보와 GC Roots 참조 체인 정보를 숙지하면 유출된 코드의 위치를 정확하게 찾을 수 있습니다🎜🎜메모리 누수가 없다면, 즉 메모리에 있는 객체는 아직 살아 있어야 합니다. 가상 머신의 메모리를 늘릴 수 있는지 확인하려면 가상 머신 힙 매개변수(-Xmx 및 -Xms)를 확인해야 합니다.🎜🎜요약: 메서드 영역과 가상 머신 스택의 오버플로 시나리오는 여기서 많이 논의되지 않습니다. 다음 기사에서는 일반적인 Java 힙 공간 OOM 문제 해결 아이디어를 주로 설명합니다.🎜JVM 메모리 분포 보기
🎜Java 애플리케이션의 PID가 15162라고 가정합니다. JVM 메모리 분포를 보려면 명령을 입력하세요jmap -heap 15162
🎜[xxx@xxx ~]# jmap -heap 15162 Attaching to process ID 15162, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.161-b12 using thread-local object allocation. Mark Sweep Compact GC Heap Configuration: MinHeapFreeRatio = 40 # 最小堆使用比例 MaxHeapFreeRatio = 70 # 最大堆可用比例 MaxHeapSize = 482344960 (460.0MB) # 最大堆空间大小 NewSize = 10485760 (10.0MB) # 新生代分配大小 MaxNewSize = 160759808 (153.3125MB) # 最大新生代可分配大小 OldSize = 20971520 (20.0MB) # 老年代大小 NewRatio = 2 # 新生代比例 SurvivorRatio = 8 # 新生代与 Survivor 比例 MetaspaceSize = 21807104 (20.796875MB) # 元空间大小 CompressedClassSpaceSize = 1073741824 (1024.0MB) # Compressed Class Space 空间大小限制 MaxMetaspaceSize = 17592186044415 MB # 最大元空间大小 G1HeapRegionSize = 0 (0.0MB) # G1 单个 Region 大小 Heap Usage: # 堆使用情况 New Generation (Eden + 1 Survivor Space): # 新生代 capacity = 9502720 (9.0625MB) # 新生代总容量 used = 4995320 (4.763908386230469MB) # 新生代已使用 free = 4507400 (4.298591613769531MB) # 新生代剩余容量 52.56726495150862% used # 新生代使用占比 Eden Space: capacity = 8454144 (8.0625MB) # Eden 区总容量 used = 4029752 (3.8430709838867188MB) # Eden 区已使用 free = 4424392 (4.219429016113281MB) # Eden 区剩余容量 47.665996699370154% used # Eden 区使用占比 From Space: # 其中一个 Survivor 区的内存分布 capacity = 1048576 (1.0MB) used = 965568 (0.92083740234375MB) free = 83008 (0.07916259765625MB) 92.083740234375% used To Space: # 另一个 Survivor 区的内存分布 capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used tenured generation: # 老年代 capacity = 20971520 (20.0MB) used = 10611384 (10.119804382324219MB) free = 10360136 (9.880195617675781MB) 50.599021911621094% used 10730 interned Strings occupying 906232 bytes.
또한 JVM이 실행되는 동안 리소스를 가장 많이 소비하는 개체를 볼 수 있습니다. jmap -histo:live 15162 | 더보기
jmap -histo:live 15162 | more
JVM 内存对象列表按照对象所占内存大小排序
instances:实例数 bytes:单位 byte class name:类名

明显看到 CustomObjTest
对象实例以及占用内存过多
可惜的是,方案存在局限性,因为它只能排查对象占用内存过高问题
其中 "[" 代表数组,例如 "[C" 代表 Char 数组,"[B" 代表 Byte 数组。如果数组内存占用过多,我们不知道哪些对象持有它,所以就需要 Dump 内存进行离线分析
JVM 메모리 객체 목록은 객체가 차지하는 메모리 크기에 따라 정렬됩니다
jmap -histo:live
인스턴스: 인스턴스 수 바이트: 단위 바이트 클래스 이름: 클래스 이름

분명히 CustomObjTest
객체 인스턴스가 너무 많은 메모리를 차지합니다안타깝게도 솔루션에는 제한이 있습니다. 너무 많은 메모리를 차지하는 객체의 문제만 해결할 수 있기 때문입니다. 여기서 "["는 배열을 나타냅니다. 예를 들어 "[C"는 Char 배열을 나타내고 "[B"는 Byte 배열을 나타냅니다. 배열 메모리가 너무 많이 차지하면 어떤 개체가 이를 보유하고 있는지 알 수 없으므로 오프라인 분석을 위해 메모리를 덤프해야 합니다jmap -histo:live
이 명령을 실행하면 JVM이 먼저 GC를 트리거한 다음 통계 정보를 수집합니다
jmap -histo:live
이 명령을 실행하면 JVM이 먼저 GC를 트리거한 다음 통계 정보를 수집합니다
Dump 파일 분석 Dump 파일은 주로 시스템 정보,
가상 머신 속성, 전체 스레드 덤프,
모든 클래스와 객체의 상태및 기타 정보
🎜를 포함하는 Java 프로세스의 메모리 이미지입니다. 또는 GC 예외가 발생하면 JVM이 발생한 것으로 의심됩니다🎜 메모리 누수🎜, 그러면 분석을 위해 덤프 파일을 내보낼 수 있습니다🎜🎜JVM 시작 매개변수 구성에 다음 매개변수를 추가하세요🎜-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./(参数为 Dump 文件生成路径)
当 JVM 发生 OOM 异常自动导出 Dump 文件,文件名称默认格式:
java_pid{pid}.hprof
上面配置是在应用抛出 OOM 后自动导出 Dump,或者可以在 JVM 运行时导出 Dump 文件
jmap -dump:file=[文件路径] [pid] # 示例 jmap -dump:file=./jvmdump.hprof 15162
在本地写一个测试代码,验证下 OOM 以及分析 Dump 文件
设置 VM 参数:-Xms3m -Xmx3m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ public static void main(String[] args) { List<Object> oomList = Lists.newArrayList(); // 无限循环创建对象 while (true) { oomList.add(new Object()); } }
通过报错信息得知,java heap space
表示 OOM 发生在堆区,并生成了 hprof 二进制文件在当前文件夹下

JvisualVM 分析
Dump 分析工具有很多,相对而言 JvisualVM、JProfiler、Eclipse Mat,使用人群更多一些。下面以 JvisualVM 举例分析 Dump 文件

列举两个常用的功能,第一个是能看到触发 OOM 的线程堆栈,清晰得知程序溢出的原因

第二个就是可以查看 JVM 内存里保留大小最大的对象,可以自由选择排查个数

点击对象还可以跳转具体的对象引用详情页面

文中 Dump 文件较为简单,而正式环境出错的原因五花八门,所以不对该 Dump 文件做深度解析
注意:JvisualVM 如果分析大 Dump 文件,可能会因为内存不足打不开,需要调整默认的内存
요약 검토
온라인에서 JVM 메모리 오버플로가 발생하는 경우 다음 단계에 따라 문제를 해결할 수 있습니다.
jmap -heap
메모리 할당이 너무 작은지 확인하세요jmap -heap
查看是否内存分配过小jmap -histo
查看是否有明显的对象分配过多且没有释放情况jmap -dump
jmap -histo
명백한 객체 할당이 너무 많고 해제되지 않음jmap -dump
JVM의 현재 메모리 스냅샷을 내보내고 JDK 또는 MAT와 같은 도구를 사용하여 스냅샷을 분석합니다. 🎜🎜🎜🎜위에서 문제를 찾을 수 없는 경우 다음이 필요합니다. 예를 들어, 네트워크 연결이나 스레드로 인해 시스템 리소스가 고갈될 수 있습니다. 🎜🎜🎜위 내용은 면접관: 온라인에서 OOM을 접하게 된다면 어떻게 해결하나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Java의 난수 생성기 안내. 여기서는 예제를 통해 Java의 함수와 예제를 통해 두 가지 다른 생성기에 대해 설명합니다.

Java의 Weka 가이드. 여기에서는 소개, weka java 사용 방법, 플랫폼 유형 및 장점을 예제와 함께 설명합니다.

Java의 Smith Number 가이드. 여기서는 정의, Java에서 스미스 번호를 확인하는 방법에 대해 논의합니다. 코드 구현의 예.

이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

Java의 TimeStamp to Date 안내. 여기서는 소개와 예제와 함께 Java에서 타임스탬프를 날짜로 변환하는 방법에 대해서도 설명합니다.

캡슐은 3 차원 기하학적 그림이며, 양쪽 끝에 실린더와 반구로 구성됩니다. 캡슐의 부피는 실린더의 부피와 양쪽 끝에 반구의 부피를 첨가하여 계산할 수 있습니다. 이 튜토리얼은 다른 방법을 사용하여 Java에서 주어진 캡슐의 부피를 계산하는 방법에 대해 논의합니다. 캡슐 볼륨 공식 캡슐 볼륨에 대한 공식은 다음과 같습니다. 캡슐 부피 = 원통형 볼륨 2 반구 볼륨 안에, R : 반구의 반경. H : 실린더의 높이 (반구 제외). 예 1 입력하다 반경 = 5 단위 높이 = 10 단위 산출 볼륨 = 1570.8 입방 단위 설명하다 공식을 사용하여 볼륨 계산 : 부피 = π × r2 × h (4
