The following knowledge is based on JDK1.8, sample project source: 👉 oom
In addition to program counters, OutOfMemoryError (OOM) exceptions are possible in several run-time areas of virtual machine memory, as described in the Java Virtual Machine specification. The purpose of this sharing is twofold:
- First, code validates what is stored in the various runtime areas described in the Java Virtual Machine specification.
- Secondly, we hope that when we encounter actual memory overflow exceptions in our daily work, we can quickly determine which area of memory overflow according to the information of exceptions, and know what kind of code will cause memory overflow in these areas, as well as how to deal with these exceptions.
The Java heap overflow (Java. Lang. OutOfMemoryError: Java heap space)
The Java heap is used to store object instances, and as long as objects are constantly created and there is a reachable path between GC Roots and objects to avoid garbage collection, overflow exceptions can occur after the maximum number of objects reaches the capacity limit.
Set the minimum value of the heap with the -xms parameter and set the maximum value of the heap to the same to avoid automatic heap expansion
Code list:
public Result<Void> heapOOM(a) {
List<OOMObject> list = new ArrayList<>();
while (true) {
list.add(newOOMObject()); }}Copy the code
Startup parameters:
-Xms60m -Xmx60m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Denv=dev -Deureka.client.register-with-eureka=false -Deureka.client.enabled=false
Copy the code
Running results:
Exception in thread "http-nio-80-exec-9" java.lang.OutOfMemoryError: Java heap space 17:37:51 2019-12-12, 576 [NioBlockingSelector BlockPoller - 1) ERROR [org.apache.tomcat.util.net.NioBlockingSelector] DirectJDKLog.java:182 - java.lang.OutOfMemoryError: Java Heap Space 2019-12-12 17:37:51:626 [http-niO-80-exec-8] ERROR [O.A.C.C.C.C. [.[localhost].[/].[dispatcherServlet]] DirectJDKLog.java:182 - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Java heap space] with root cause java.lang.OutOfMemoryError: Java heap spaceCopy the code
The general solution is to analyze the heap Dump snapshot through the Memory image analysis tool (MAT) first, focusing on confirming whether the objects in Memory are necessary, that is, to distinguish between Memory Leak and Memory Overflow.
If it is a memory leak, you can further check the leak object’s reference chain to GC Roots through the tool. You can then find out what path the leak objects took to associate with CG Roots and prevent the garbage collector from automatically collecting them. With the type information of the leaked object and the reference chain information of GC Roots, the location of the leaked code can be more accurately located.
If there is no leak, you should check the heap parameter of the virtual machine (-xms-Xmx) to see if it can be increased compared to the physical memory of the machine. You can also check the code to see if some objects are declared too long and hold state too long to try to reduce the memory consumption of the program’s runtime.
The virtual machine stack and the local method stack overflow
Since there is no distinction between the virtual machine stack and the local method stack in the HotSpot VIRTUAL machine, for HotSpot, the -xoss parameter (which is the local method stack size) exists but is actually invalid and the stack size is only set by the -xss parameter. With respect to the virtual machine stack and the local method stack, two exceptions are described in the Java Virtual Machine specification:
- StackOverFlowError is thrown if the stack depth requested by the thread is greater than the maximum depth allowed by the virtual machine.
- OutOfMemoryError is thrown if the virtual machine cannot allocate sufficient memory space while extending the stack.
Test code:
public class JavaVMStackSOF {
private int stackLength = 1;
public void stackLeak(a) { stackLength++; stackLeak(); }}Copy the code
Running results:
2019-12-13 11:01:00,511 [http-nio-80-exec-9] ERROR [O.A.C.C.C.C. [. DirectJDKLog.java:182 - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause java.lang.StackOverflowError: null at com.gaodun.ts.oom.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:15)Copy the code
In a single thread, a StackOverflowError is raised when memory cannot be allocated due to the large stack frame (the virtual machine stack is too small).
You can also use the -xss argument to reduce stack memory, and you can also throw StackOverflowError.
Metaspace overflow
Similar in nature to permanent generations, meta-spaces are implementations of method areas in the JVM specification. However, the biggest difference between a meta-space and a permanent generation is that the meta-space is not in the virtual machine, but uses local memory. Therefore, by default, the size of a meta-space is limited only by local memory, but you can specify the size of a meta-space with the following parameters:
- -xx :MetaspaceSize, the initial size of the space, which triggers garbage collection for type offloading and is adjusted by the GC: if a large amount of space is freed, the value is reduced appropriately; If very little space is freed, increase this value appropriately until MaxMetaspaceSize is exceeded.
- -xx :MaxMetaspaceSize. The maximum space is unlimited by default.
Test code:
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
returnmethodProxy.invokeSuper(o, objects); }}); enhancer.create(); }Copy the code
Startup parameters: -Xms1024m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Denv=dev -Deureka.client.register-with-eureka=false -Deureka.client.enabled=false
Running results:
Exception in thread "SimplePauseDetectorThread_0" Exception in thread "http-nio-80-exec-1" java.lang.OutOfMemoryError: Metaspace
java.lang.OutOfMemoryError: Metaspace
Copy the code
- Java7, the constant pool is stored in the heap, the constant pool is equivalent to the permanent generation, so the permanent generation is stored in the heap.
- Java8 has eliminated the entire permanent generation region and replaced it with a meta-space. No further adjustments are made to the constant pool.
Native direct memory overflow
DirectMemory capacity can be specified by -xx :MaxDirectMemorySize. If not specified, it defaults to the maximum Java heap size (specified by -xmx)
Retrieving Unsafe instances directly for memory allocation via reflection. (The getUnsafe() method of the Unsafe class restricts returning instances only to the bootstrap class loader, meaning that the designers wanted only classes in rt.jar to use Unsafe’s functionality.) Test code:
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
// 1M
unsafe.allocateMemory(1024 * 1024);
}
Copy the code
Startup parameters: -Xms100m -Xmx100m -XX:MaxDirectMemorySize=100m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Denv=dev -Deureka.client.register-with-eureka=false -Deureka.client.enabled=false
Running results:
[O.A.C.C.C. [.[localhost].[/].[dispatcherServlet]] DirectJDKLog.java:182 - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.OutOfMemoryError] with root cause java.lang.OutOfMemoryError: null at sun.misc.Unsafe.allocateMemory(Native Method)Copy the code
An obvious feature of Heap Dump files due to direct memory overflow is that there are no obvious exceptions in Heap Dump files. If you find that the Dump file is very small after OOM and NIO is used directly or indirectly in your application, consider whether this is the cause.
Problem extension
- JVM runtime data area &JVM memory model
- Introducing the Java memory area (runtime data area)
- Java object creation process (5 steps, recommended to be able to write and know what the virtual machine does at each step)
- Two ways to access and locate objects (handle and direct pointer)
- Relationship between method region and permanent generation
- Why replace PermGen with MetaSpace?
- String class and constant pool
- Eight basic types of wrapper classes and constant pools
- OOM analysis
- What are the JVM garbage collectors and what are their respective garbage collection algorithms
- JVM tuning experience
Reference documentation
- In-depth Understanding of the Java Virtual Machine