Watch the video to learn how to initiate the process of OOM and troubleshooting, and video .
Through this video to learn about a lot of knowledge and methods of debug JVM recorded as follows.
problem
There are three common OutOfMemoryError:
- java.lang.OutOfMemoryError: Java heap space heap space
- java.lang.OutOfMemoryError: Java metaspace dimensional space
- java.lang.OutOfMemoryError: Java perm gen permanent generations
step
Achieve OOM
Create a OOM.java file, as follows, since the full implementation of java files on the command line window, although the project file in the package, but the package name will be added in the command line compiler error, so do not add:
import java.util.HashMap;
import java.util.Map;
public class OOM {
public static void main(String[] args) {
Map cache = new HashMap();
for (int i = 0; i < 128; i++) {
cache.put(i, new byte[1024 * 1024]);
}
}
}
This time using the javac command to compile: javac OOM.java
will appear warning, because the Map does not use generics, can be ignored.
Use the java command to run OOM.class file, then you need to set the size of memory to run, because a bunch of objects command creates a size of 128 m:
F:\Code\Java\java-demo\src\oom>java -Xmx128m OOM
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at OOM.main(OOM.java:8)
So far, causing OutOfMemoryError success.
Get a snapshot Heap Dump
Two methods:
the first
Add parameters when you start java virtual machine using the command -XX:+HeapDumpOnOutOfMemoryError
:
F:\Code\Java\java-demo\src\oom>java -Xmx128m -XX:+HeapDumpOutOfMemoryError OOM
Unrecognized VM option 'HeapDumpOutOfMemoryError'
Did you mean '(+/-)HeapDumpOnOutOfMemoryError'?
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
F:\Code\Java\java-demo\src\oom>java -Xmx128m -XX:+HeapDumpOnOutOfMemoryError OOM
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid12992.hprof ...
Heap dump file created [122989308 bytes in 0.114 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at OOM.main(OOM.java:8)
Here I will be the first entry errors also wrote in, just to show Errors also occur during the experiment, but I think jdk will be prompted to add the (+/-)HeapDumpOnOutOfMemoryError
parameters, this time by being given the information to know the original parameter wrong , and a second input on the correct implementation heap Dump I want to get a snapshot, which can help me analyze the information heap memory.
In this case more than a file directory java_pid12992.hprof
, in the third step will be to learn how to analyze the snapshot file. However, before the analysis, and then try the second method to get a snapshot.
second
The first method is to add parameters before running a good snapshot, but if you are in a program that is already running, how to add parameters can get a snapshot of it?
First, the above-described modified file to slow down the speed of generating the OOM:
import java.util.HashMap;
import java.util.Map;
public class OOM {
public static void main(String[] args) throws Exception {
Map cache = new HashMap();
for (int i = 0; i < 128; i++) {
Thread.sleep(1000);
cache.put(i, new byte[1024 * 1024]);
}
}
}
Use jps
the command java can see the currently running process:
F:\Code\Java\java-demo\src\oom>jps
17160 GradleDaemon
8984 Jps
Next will use the jmap
command to add a snapshot of the process, look at how you can use this command:
F:\Code\Java\java-demo\src\oom>jmap -help
Usage:
jmap [option] <pid>
(to connect to running process)
jmap [option] <executable <core>
(to connect to a core file)
jmap [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server)
where <option> is one of:
<none> to print same info as Solaris pmap
-heap to print java heap summary
-histo[:live] to print histogram of java object heap; if the "live"
suboption is specified, only count live objects
-clstats to print class loader statistics
-finalizerinfo to print information on objects awaiting finalization
-dump:<dump-options> to dump java heap in hprof binary format
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file=<file> dump heap to <file>
Example: jmap -dump:live,format=b,file=heap.bin <pid>
-F force. Use with -dump:<dump-options> <pid> or -histo
to force a heap dump or histogram when <pid> does not
respond. The "live" suboption is not supported
in this mode.
-h | -help to print this help message
-J<flag> to pass <flag> directly to the runtime system
Input jmap -help
can see a lot of parameters, I pick out the part which requires the use of:
F:\Code\Java\java-demo\src\oom>jmap -help
-dump:<dump-options> to dump java heap in hprof binary format
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file=<file> dump heap to <file>
Example: jmap -dump:live,format=b,file=heap.bin <pid>
jmap -dump:live,format=b,file=heap.bin <pid>
Remember this command, so when you need to add this while running.
Like the first method, like compile and run:
// compile
F:\Code\Java\java-demo\src\oom>javac OOM.java
// run
F:\Code\Java\java-demo\src\oom>java -Xmx128m OOM
······ // will wait about two minutes, and then print OutOfMemoryError
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at OOM.main(OOM.java:9)
This time need to open another command line window, use the jps
View process running number, this number is behind the pid parameters:
F:\Code\Java\java-demo\src\oom>jps
16272 OOM
8592 Jps
17160 GradleDaemon
Input parameters:
F:\Code\Java\java-demo\src\oom>jmap -dump:live,format=b,file=16272.hprof 16272
Dumping heap to F:\Code\Java\java-demo\src\oom\16272.hprof ...
Heap dump file created
At this time, referring to the directory can be seen, there are two snapshots, respectively, is done using two methods:
2019/11/30 14:10 105,162,801 16272.hprof
2019/11/30 13:50 122,989,308 java_pid12992.hprof
2019/11/30 14:08 651 OOM.class
2019/11/30 14:07 307 OOM.java
Explanation
These methods are the parameters HotSpot virtual machine, that is, may not apply the same procedures and parameters to get the Heap Dump snapshot on other virtual machines.
JVM threw OOM, but the JVM is still running, but more slowly due to insufficient memory response, this time if some operations are not memory-intensive presence can still perform.
Analysis OOM
OOM is how did it?
Need to know the principles of GC, GC judgment of garbage is memory object reachability analysis, GC Roots objects are considered the starting point, starting from the GC Root, has been searching down. GC Root reachable objects do not need to recover other objects to clean up.
At this point there may be cases has not been cleaned up some objects appeared, heap full, generated OOM.
It is also possible that the new object is too large, but without a large heap space can accommodate (since the previous cleaning space such as a heap fragmentation), generated at this time OOM.
Generating the OOM summarized reasons: code issue 50% (according to the present embodiment OOM.java), 40% Allocation (-Xmx128m the present embodiment), is really not enough memory is 10%.
Analysis Snapshot common tools
VisualVM
VisualVM, JDK 9+ need to download their own version, this machine uses JDK 8, the command line jvisualvm
you can call.
Look at the JDK comes with VisualVM, enter the JDK bin directory, look at the frequently used programs:C:\Program Files\Java\jdk1.8.0_221\bin
program | effect |
---|---|
jar.exe | Bale |
java.exe | Start the virtual machine, run the bytecode files |
javac.exe | Compile java files |
javadoc.exe | Api file generation |
javap.exe | Decompile, view bytecode |
jcmd.exe | Virtual machine running commanding |
jdb.exe | debugging |
jmap.exe | Create a snapshot Dump |
jps.exe | All current java process running on the computer |
jstack.exe | |
jstat.exe | Check the status of the entire jvm |
jvisualvm.exe | Call VisualVM |
Simply run the program to see what happens, enter the command jvisualvm
, the command line window to run java -Xmx128m OOM
, then you can see the emergence of local OOM this process, you can double-click the connection, and then see the virtual machine input parameters at startup.
Can be seen opening the monitor heap Metaspace is progressively larger.
Just select the snapshot Heap Dump loaded, you can check the inside of the case:
Occupy memory can be seen the most is byte[]
,
MAT
Open source Eclipse Memory Analyzer, can be downloaded from the official website. Import snapshot earlier.
The following two main areas where analysis is a snapshot:
Histogram
The main view and selected Class object that raised the OOM. Examples of statistical objects of each class, there can be seen two portions Shallow Heap and Retained Heap.
would like to explain the concept retained by the following description: A hypothesis objects need to be recovered, this recovery time can be simultaneously A, C, E three objects, this time corresponding Retained Heap relatively large.
If this is the case below, the recovery of only the object A, the object B as an object points to C, this time corresponds Retained Heap becomes small.
Dominator Tree
占据内存空间很大的对象以及使他们一直存在的原因是什么,截了个图,可以看到是 main 线程保留着这些对象
Leak Suspects
也是主要使用的功能,可以分析可能发生溢出的原因。
Top Components
给出占据堆内存超过 1% 的组件。
Heap Dump 分析
一般来说有两个原因导致 heap 溢出:
Metaspace / PermGen —— Class 对象没有被正确的释放,尤其是 ClassLoader,一般来说自己不写 ClassLoader 里面最多只有几十个,如果发现 ClassLoader 数量过多则应该在 Metaspace / PermGen 寻找问题
Heap space —— 瞄准占空间最大的对象
通过这些工具的查看,找到溢出的 Class 对象,使用 Merge Shortest Paths to GC Roots
功能就可以找到一些 Path to GC Roots
路径,这些路径显示了这些对象是如何相互引用以及避免了垃圾回收,最终引发 OOM 的 Error 信息。找到这些信息后,通过修改代码规避这些问题,修复这些 bug。