Analysis and troubleshooting of common OOM exceptions
Java out of memory
The java heap is used to store object instances. If objects are created continuously and there is a reachable path between the GC Root and the object, the garbage collection mechanism will not clean up these objects. When the number of objects reaches the maximum heap capacity limit, memory will be generated. Overflow exception.
Causes of Java heap overflow
- Unable to allocate object in java heap
- The application saves objects that cannot be collected by GC
- Application overuses finalizers
Solutions
- Find key error messages such as
java.lang.StackOverflowError
java.lang.OutOfMemoryError:java heap space
java.lang.OutOfMemoryError:GC overhead limit exceeeded
java.lang.OutOfMemoryError:Direct buffer memory
java.lang.OutOfMemoryError:unable to create new native thread
java.lang.OutOfMemoryError:Metaspace
- Find the ID (PID) of the java process, and use the jps -vl command to find the PID of the java process and the jvm parameters set at startup.
jps -vl
- View the allocation size and usage of heap memory in the new generation and the old generation
jmap -heap PID
[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.
- Query the most memory-consuming objects, and the information of the surviving objects will be displayed in the form of a table, and sorted according to the occupied memory size. The information includes ranking, number of instances, occupied memory size, class name
jmap -histo:live PID | more
- Dump file analysis
Dump file is the memory image of the Java process, which mainly includes system information, virtual machine properties, complete thread dump, status of all classes and objects, etc. Add the following parameters to the JVM startup parameter
configuration
- -XX:+HeapDumpOnOutOfMemoryError
- -XX:HeapDumpPath=./ (parameter is the dump file generation path)
JVM startup parameter configuration adds the following parameters. The
above configuration is to automatically export the dump after the application throws OOM, or the dump file can be exported when the JVM is running
jmap -dump:file=[文件路径] [pid]
# 示例
jmap -dump:file=./jvmdump.hprof 15892
Demo
设置 VM 参数:-Xms3m -Xmx3m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./
public static void main(String[] args) {
List<Object> oomList = Lists.newArrayList();
// 无限循环创建对象
while (true) {
oomList.add(new Object());
}
}
Summarize
If you encounter JVM memory overflow online, you can check
jmap -heap in the following steps to see if the memory allocation is too small
jmap -histo to see if there are obvious objects allocated too much and not released
jmap -dump exports the current memory snapshot of the JVM, and uses tools such as JDK or MAT to analyze the snapshot