Because the interviewer only mentioned OOM, but Java Of OOM There are many types ：
Heap overflow （“java.lang.OutOfMemoryError: Java heap space”）
Permanent generation overflow （“java.lang.OutOfMemoryError:Permgen space”）
Cannot create thread （“java.lang.OutOfMemoryError:Unable to create new native thread”）
OOM stay 《Java Virtual machine specification 》 in , Divider counter , Several other runtime areas of virtual machine memory can occur OOM, What is the purpose of this article ?
Pass code verification 《Java Virtual machine specification 》 The contents stored in each runtime area described in
When encountering an actual memory overflow exception at work , It can quickly know which area of memory overflow is according to the abnormal prompt information , Know what code might cause memory overflow in these areas , And how to deal with these exceptions .
The code of this paper is written by the author based on the OpenJDK 8 In HotSpot Actual testing has been done on the virtual machine .
<>1 Java Heap overflow
Java Heap is used to store object instances , Just keep creating objects , And promise GC
Roots There are reachable paths to objects to avoid GC Mechanism to clear these objects , The number of objects increases , When the total capacity reaches the capacity limit of the maximum heap, a memory overflow exception will occur .
limit Java The size of the heap 20MB, Non extensible
Can let the virtual machine in the event of memory overflow exception Dump Output the current heap dump snapshot .
<> case 1
* report errors
Java Heap memory OOM It is the most common memory overflow exception scenario in practical application . appear Java When heap memory overflows , Exception stack information “java.lang.OutOfMemoryError” Further hints will be followed “Java
Now that it happened , How to solve this memory area exception ?
Generally, the memory image analysis tool is used first （ as jprofile） yes Dump Analysis of the heap dump snapshot .
The first step is to confirm that the OOM Is the object of the necessary , That is to say, we should first make clear what is the reason
Memory leak （Memory Leak）
Or memory overflow （Memory Overflow）
The figure below shows how to use the jprofile Open heap dump snapshot file （java_pid44526.hprof）
If it's a memory leak , You can view the leaking objects to GC Roots Reference chain of , How to find the reference path of the leaking object , With which GC
Roots Related , So that the garbage collector can't recycle them , Based on the type information of the leaked object and its GC
Roots Information of reference chain , Generally, you can locate these objects more accurately , And then find out the specific location of the memory leak code .
If it's not a memory leak , That is, all objects in memory must survive , Then we should ：
* inspect JVM Reactor parameters （-Xmx And -Xms） Settings for , Compared with machine memory , See if there is room for upward adjustment
* Check the code again to see if the life cycle of some objects is too long , Long holding time , The design of storage structure is unreasonable , Minimize the number of procedures Memory consumption in row period
The above is the treatment Java A brief thought of heap memory problem .
<> case 2
JVM Start parameter setting ：
-Xms5m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
* JVM Changes in heap space
Usage size of heap , Sudden shaking ! When a thread throws OOM after , All the memory resources it occupies will be released , It will not affect the normal operation of other threads !
So when a thread overflows , Other threads in the process can still run as usual .
happen OOM In general, the thread of will die , That is, it will be terminated , The amount of time occupied by the object held by the thread heap They're all going to be killed gc It's over , Free memory . Because it happened OOM Before that gc, Even if other threads work properly , Also because of frequent gc Have a greater impact .
Heap overflow and stack overflow , The conclusion is the same .
<>2 VM Stack / Local method stack overflow
because HotSpot JVM There is no distinction between virtual machine stack and local method stack , therefore HotSpot Of -Xoss parameter （ Sets the size of the local method stack ） Although there is , But it had no effect , Stack capacity can only be determined by -Xss
Parameter setting .
On virtual machine stack and local method stack ,《Java Virtual machine specification 》 The following exception is described ：
* If the stack depth requested by the thread is greater than the maximum allowed by the virtual machine , Will be thrown StackOverflowError abnormal
* If the stack memory of virtual machine is allowed to expand dynamically , When the expansion stack capacity can not apply for enough memory , Will be thrown OutOfMemoryError abnormal
《Java Virtual machine specification 》 Explicit permission JVM We can choose whether to support stack dynamic expansion or not , and HotSpot The choice of virtual machine is not to support extension
, So unless the thread is created to apply for memory, it will appear because it can not get enough memory OOM, Otherwise, when the thread is running, it will not cause memory overflow due to expansion , Only because the stack capacity can't hold the new stack frame StackOverflowError.
<> How to verify ?
Do two experiments , First in single thread operation , Try these two behaviors to see if they can make you feel better HotSpot OOM：
<> use -Xss Reduce stack memory capacity
throw StackOverflowError abnormal , When an exception occurs, the stack depth of the output is reduced accordingly .
Different versions of Java Virtual machines and different operating systems , The minimum stack size may be limited , This mainly depends on the memory paging size of the operating system . For example, the parameters in the above method -Xss160k It can be used normally 62 position macOS Under the system JDK
8, But if it's used for 64 position Windows Under the system JDK
11, The minimum stack size cannot be less than 180K, And in Linux The next value might be 228K, If it's below this minimum limit ,HotSpot The following prompt will be given when the virtual machine starts ：
The stack size specified is too small, Specify at
<> Define a large number of local variables , Increase the length of the local variable table in this method frame
So whether it is because the stack frame is too small or the virtual machine stack capacity is too small , When the new stack frame memory cannot be allocated , HotSpot
Throw it all away SOF. It can be implemented on a virtual machine that allows dynamic stack expansion , The same code leads to different situations .
If the test is not limited to single thread , Instead, new threads are constantly created , stay HotSpot It's going to happen on the Internet OOM. But that's what happens OOM There is no direct relationship between stack space and stack space , Mainly depends on os Memory usage status . Even in this case , The more memory is allocated to the stack of each thread , On the contrary, the more likely it is to happen OOM.
It's not hard to understand ,os There is a limit on the amount of memory allocated to each process , such as 32 position Windows The maximum memory limit for a single process is 2G.HotSpot Provide parameters that can be controlled Java The maximum amount of memory in the heap and method area , The remaining memory is 2G（os limit ） Minus maximum heap capacity , Then subtract the maximum method area capacity , Because the program counter consumes very little memory , Negligible , If the direct memory and the memory consumed by the virtual machine process itself are also removed , The rest of the memory is allocated by the virtual machine stack and the local method stack . Therefore, the larger the stack memory allocated to each thread , The fewer threads that can be created , The easier it is to run out of the remaining memory when creating a thread ：
* result Exception in thread "main" java.lang.OutOfMemoryError: unable to create
appear SOF Time , There will be a clear error stack to analyze , It is relatively easy to locate the problem . If used HotSpot Virtual machine default parameters , Stack depth in most cases （ Because the frame size of each method is not the same ） arrive 1000~2000 no problem , For normal method calls （ Including recursive calls that cannot do tail recursive optimization ）, This depth should be enough . But if it is the establishment of too many threads caused by memory overflow , The number of threads cannot be reduced or replaced 64 Bit virtual machine , We can only reduce the maximum heap and stack capacity in exchange for more threads . This kind of pass “ Reduce memory ” Methods to solve memory overflow , If you don't have experience in this area , Generally, it's hard to think of . It is also because this kind of problem is more hidden , from
JDK 7 rise , In the above prompt information “unable to create native thread” behind , The reason for virtual opportunity is that “possibly
#define OS_NATIVE_THREAD_CREATION_FAILED_MSG "unable to create native thread:
possibly out of memory or process/resource limits reached"
<>3 Method area and runtime constant pool overflow
The runtime constant pool is part of the method area , So the overflow test of these two areas can be put together .
HotSpot from JDK 7 Step by step “ Go to permanent generation ”, stay JDK 8 Instead of permanent generation, meta space is completely used in , How to use the method area “ Permanent generation ” still “ Meta space ” To achieve , What is the impact on the process .
String::intern() It's a local method ： If the string constant pool already contains a String The string of the object , The string representing the string in the pool String Object reference ; otherwise , This will be String Object to the constant pool , And return to this String Object reference .
stay JDK6 Or before HotSpot virtual machine , Constant pools are allocated in the permanent generation , You can use the following two parameters ：
Limit the size of permanent generations , It can indirectly limit the capacity of the constant pool ,
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space at
java.lang.String.intern(Native Method) at