JVM memory management: goes deep into the Java memory area and OOM

Source: Internet
Author: User

Address: http://www.iteye.com/topic/802573

There is a wall between Java and C ++ that is surrounded by the dynamic memory allocation and garbage collection technology. The people who look at it want to go in, but the people inside the wall want to come up with it.

 

Overview:

For developers engaged in C and C ++ program development, in the memory management field, they are the emperors with the highest power and the working people who perform the most basic work. They have the "ownership" of every object and are responsible for the maintenance from the beginning to the end of every object's life.

 

For Java programmers, there is no need to write a pair of delete/free for each new operation. It is not prone to content leakage and memory overflow errors. It seems that the JVM manages the memory well. However, it is precisely because the Java programmer has handed over the memory control power to the JVM. Once there is a leak or overflow, if you do not know how the JVM uses the memory, troubleshooting will be very difficult.

 

VM runtime data area

Various data regions are used during JVM Java program execution. These regions have their own purposes, Creation Time, and destruction time. According to the Java Virtual Machine specification (version 2) (hereinafter referred to as the VM Spec), the JVM includes the following runtime data regions:

 

1. Program Counter (Program Counter Register ):

 

Each Java thread has a program counter to save the instruction of the current method that the program executes. For non-Native methods, this region records the address of the VM primitive being executed, if the Natvie method is being executed, this region is null (undefined ). This memory region is the only region in the VM Spec that does not specify any OutOfMemoryError conditions.

 

2. Java Virtual Machine Stacks)

Like program counters, the life cycle of the VM stack is also the same as that of the thread. The VM stack describes the Memory Model of Java method calls. Each method creates a Frame when it is executed) stores local variable tables, Operation stacks, dynamic links, method portals, and other information. The call to each method is complete, which means that a frame is in the VM stack and is transferred to the output stack. Later, we will focus on the local variable table section in the VM stack.

Some people often distinguish Java memory from Heap memory and Stack memory. The actual region is far more complex than this viewpoint, this division only indicates that the memory area closely related to the variable definition is the two. The "stack" is described later, and the "stack" refers to the local variable table of each frame in the VM stack. The local variable table stores various scalar types (boolean, byte, char, short, int, float, long, and double) and object references (not the object itself, is just a reference pointer), method return address, etc. Long and double occupy two local variable spaces (32bit), and the other one. The local variable table is allocated when you enter the method. when you enter a method, it is completely determined how many local variables need to be allocated in the frame, during method running, the size of the local variable table is not changed.

In the VM Spec, this region is set to 2: If the stack depth requested by the thread is greater than the depth allowed by the virtual machine, an StackOverflowError exception will be thrown; if the VM stack can be dynamically expanded (a VM stack with a fixed length is allowed in the VM Spec), an OutOfMemoryError exception is thrown when the memory cannot be applied for during expansion.

3. Native Method Stacks)

The role of the local method stack is similar to that of the VM stack, except that the VM Stack runs the VM primitive service, and the local method stack serves the Native method used by the VM. The language, method, and structure of its implementation are not mandatory. Even some virtual machines (such as the Sun Hotspot Virtual Machine) directly combine the local method stack and the VM stack into one. Like the VM stack, StackOverflowError and OutOfMemoryError are thrown in this region.

4. Java Heap)

For most applications, Java heap is the largest memory managed by virtual machines. Java heap is shared by all threads and is created when the VM is started. The only purpose of Java heap is to store object instances. Most object instances are allocated here. This is described in the VM Spec: all instances and arrays are allocated on the stack (original: the heap is the runtime data area from which memory for all class instances and arrays is allocated), but after The emergence of escape analysis and scalar replacement optimization technology, the description of the VM Spec is not so accurate.

In the Java heap, there are more detailed divisions: the new generation and the old generation, and a little more detailed: eden, from kernel vor, to kernel vor, and even more fine-grained local thread allocation buffer (TLAB, no matter how the Java heap is divided, the objective is to better recycle the memory or allocate the memory faster. In this chapter, we will only discuss the role of the memory area, for details about the above regions in the Java heap, see Chapter 2 JVM memory management: Deep Garbage Collector and memory allocation policies.

According to the requirements of the VM Spec, the Java heap can be in physically discontinuous memory space, which is logically sequential, just like our disk space. You can choose to implement a fixed or scalable Virtual Machine. However, all current commercial virtual machines are implemented according to scalability (controlled by-Xmx and-Xms ). If memory cannot be allocated in the heap and the heap cannot be expanded, an OutOfMemoryError error will be thrown.

5. Method Area)

The "Method Area" may not have many people who know it. If it is called "Permanent Generation", there may be more fans. It also has an alias called Non-Heap (Non-Heap), but on the VM Spec, the method area is a logical part of the Heap (original: the method area is logically part of the heap). the problem of this name is easy to misunderstand and we will not be confused here.

The method area stores the structure information of each Class, including the constant pool, field description, and method description. The VM Space Description imposes very loose restrictions on this region. In addition to the Java heap and does not require continuous memory, you can also choose a fixed size or scalability, or even choose not to implement garbage collection. Relatively speaking, the garbage collection behavior rarely occurs in this region, however, it is not as described that GC will not occur on permanent generation (at least for mainstream commercial JVM implementations ), GC is mainly used to recycle the constant pool and unload the class. Although the "score" of the collection is generally unsatisfactory, especially when the class is detached, the conditions are quite harsh.

6. Runtime Constant Pool)

In addition to Class version, field, method, interface, and other descriptions, the Class file also contains a constant table (constant_pool table) used to store known constants during the compilation period, this part of content will be stored in the Method Area (permanent generation) after the class is loaded. However, the Java language does not require constants to enter the constant table content of the Class in the compilation period before entering the constant pool of the method area, you can also add new content to the constant pool (the most typical String. intern () method ).

The runtime constant pool is part of the method area and is naturally restricted by the method Area Memory. When the constant Pool cannot be applied to the memory, an OutOfMemoryError exception is thrown.

 

7. Direct Memory)

Direct Memory is not part of the data zone of the VM runtime. It is the local memory instead of the zone directly managed by the VM. However, this part of memory also causes an OutOfMemoryError exception, so we will describe it here.

The NIO class was added to JDK1.4, introducing an I/O Method Based on channels and buffers. It can be directly allocated to the local memory through the Native function library on the local machine, then, use a DirectByteBuffer object stored in the Java heap as a reference to the memory. This can significantly improve performance in some scenarios, because it avoids copying data back and forth between the Java pair and the local heap.

Obviously, the direct memory allocation on the local machine is not limited by the Java heap size, but the memory must still be limited by the physical memory (including the SWAP area or Windows virtual memory) on the local machine, when a server administrator configures JVM parameters, the server administrator sets parameters such as-Xmx based on the actual memory, but often ignores the Direct Memory, this causes an OutOfMemoryError to occur when dynamic expansion occurs because the total amount of each memory area exceeds the physical memory limit (including physical and operating system-level restrictions.

 

Actual OutOfMemoryError

In the above area, in addition to the program counter, other cases described in the VM Spec that generate the OutOfMemoryError (hereinafter referred to as OOM), we will simulate it in practice, through a few simple pieces of code, cause OOM exceptions in the corresponding region to deepen understanding, and introduce some memory-related virtual machine parameters. The code below is based on the implementation of Sun Hotspot virtual machine version 1.6. For different versions of virtual machines in different companies, the parameters and program running results may be different.

 

JavaHeap

 

Java heap stores object instances. Therefore, as long as an object is continuously created and there is an reachable path between the GC Roots and the object, an OOM exception occurs. In the test, the size of the Java heap is limited to 20 mb and cannot be extended. The parameter-XX: + HeapDumpOnOutOfMemoryError is used to let the VM Dump out the memory image in case of an OOM exception for analysis. (For details about Dump Image File analysis, see Chapter 3 JVM memory management: Deep JVM Memory exception analysis and tuning.)

Listing 1: Java heap OOM Test

/**

* VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

* @author zzm

*/

public class HeapOOM {

static class OOMObject {

}

public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();

while (true) {
list.add(new OOMObject());
}
}
}

Running result:

Java. lang. OutOfMemoryError: Java heap space

Dumping heap to java_pid3404.hprof...

Heap dump file created [22045981 bytes in 0.663 secs]

 

 

VMStack and local method Stack

 

The hot spot virtual machine does not distinguish between the VM stack and the local method stack. Therefore, the-Xoss parameter is actually invalid, and the stack capacity is set only by the-Xss parameter. The VM stack and local method stack have two types of exceptions described in the VM Spec: StackOverflowError and OutOfMemoryError. When the stack space cannot be further allocated, whether the memory is too small or the stack is too large is actually two descriptions of the same thing in a sense. In my experiment, for single-threaded applications, the following three methods cannot generate OOM for virtual machines. All the results are SOF exceptions.

 

1. Use the-Xss parameter to reduce the stack memory capacity. Result: The stack depth decreases accordingly when an SOF exception is thrown.

2. Define a large number of local variables and increase the frame length of the method. Result: The stack depth decreases accordingly when an SOF exception is thrown.

3. Create several complex objects that define many local variables, enable escape analysis and scalar replacement options, and allow the JIT compiler to allocate objects in the stack after they are split. Result: The actual effect is the same as that of the second vertex.

 

Listing 2: VM stack and local method stack OOM test (only used as a 1st-point test program)

/**

* VM Args:-Xss128k

* @author zzm

*/
public class JavaVMStackSOF {

private int stackLength = 1;

public void stackLeak() {
stackLength++;
stackLeak();
}

public static void main(String[] args) throws Throwable {
JavaVMStackSOF oom = new JavaVMStackSOF();
try {
oom.stackLeak();
} catch (Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}

Running result:

Stack length: 2402

Exception in thread "main" java. lang. StackOverflowError

At org. fenixsoft. oom. JavaVMStackSOF. stackLeak (JavaVMStackSOF. java: 20)

At org. fenixsoft. oom. JavaVMStackSOF. stackLeak (JavaVMStackSOF. java: 21)

At org. fenixsoft. oom. JavaVMStackSOF. stackLeak (JavaVMStackSOF. java: 21)

 

If a thread is continuously established in a multi-threaded environment, an OOM exception can be generated. However, basically, this exception is not directly related to the insufficient VM stack space, even the more memory allocated to the VM stack of each thread, the more likely the OOM exception will be generated.

 

The reason is actually quite understandable. The memory allocated to each process by the operating system is limited. For example, the 32-bit Windows system is limited to 2 GB, java heap and method area size JVM has a parameter that can limit the maximum value, the remaining memory is 2 GB (Operating System Limit)-Xmx (maximum heap)-MaxPermSize (Maximum Method Area ), the program counter consumes a small amount of memory and can be ignored. If the memory consumed by the virtual machine process itself is not calculated, the remaining memory is allocated to the VM stack of each thread and the local method stack, the more memory is allocated to the VM stack in each thread, the more likely it is to exhaust the remaining memory.

 

Listing 3: OOM exceptions caused by thread Creation

/**

* VM Args:-Xss2M (larger at this time)

* @ Author zzm

*/

Public class JavaVMStackOOM {

Private void dontStop (){
While (true ){
}
}

Public void stackLeakByThread (){
While (true ){
Thread thread = new Thread (new Runnable (){
@ Override
Public void run (){
DontStop ();
}
});
Thread. start ();
}
}

Public static void main (String [] args) throws Throwable {
JavaVMStackOOM oom = new JavaVMStackOOM ();
Oom. stackLeakByThread ();
}
}

Note: If you want to run the above Code, remember to save the current work on the disk. The above code may cause a high risk of freezing the operating system.

 

Running result:

Exception in thread "main" java. lang. OutOfMemoryError: unable to create new native thread

Runtime constant pool

 

To add content to the constant pool, use the Native method String. intern. Since the constant pool is allocated in the method area, we only need to use-XX: PermSize and-XX: MaxPermSize to limit the size of the constant pool. The implementation code is as follows:

 

Listing 4: OOM exceptions caused by the running frequent pool

/**
* VM Args:-XX: PermSize = 10 M-XX: MaxPermSize = 10 M
* @ Author zzm
*/
Public class RuntimeConstantPoolOOM {

Public static void main (String [] args ){
// Use List to keep constant pool reference and suppress Full GC to reclaim constant pool behavior
List <String> list = new ArrayList <String> ();
// The PermSize of 10 m is sufficient to generate OOM in the integer Range.
Int I = 0;
While (true ){
List. add (String. valueOf (I ++). intern ());
}
}
}

Running result:

Exception in thread "main" java. lang. OutOfMemoryError: PermGen space

At java. lang. String. intern (Native Method)

At org. fenixsoft. oom. RuntimeConstantPoolOOM. main (RuntimeConstantPoolOOM. java: 18)

 

 

Method Area

 

As mentioned above, the method area is used to store Class-related information. Therefore, in this area, we use CGLib to directly operate on bytecode to dynamically generate a large number of classes. It is worth noting that, in this example, the simulated scenario is often used in actual applications: Currently, many mainstream frameworks, such as Spring and Hibernate, are used to enhance the class, CGLib and other bytecode technologies are used. When more classes are enhanced, a larger method area is required to ensure that dynamically generated classes can be loaded into the memory.

 

Listing 5: Using CGLib to cause OOM exceptions in the Method Area

/**
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
* @author zzm
*/
public class JavaMethodAreaOOM {

public static void main(String[] args) {
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
});
enhancer.create();
}
}
static class OOMObject {
}
}

Running result:

Caused by: java. lang. OutOfMemoryError: PermGen space

At java. lang. ClassLoader. defineClass1 (Native Method)

At java. lang. ClassLoader. defineClassCond (ClassLoader. java: 632)

At java. lang. ClassLoader. defineClass (ClassLoader. java: 616)

... 8 more

 

Local Direct Memory

 

The DirectMemory capacity can be specified through-XX: MaxDirectMemorySize. If this parameter is not specified, it is the same as the Java heap (-Xmx) by default. The following code goes beyond DirectByteBuffer, the getUnsafe () method of the Unsafe class directly obtains the Unsafe instance for memory allocation (the Unsafe class's getUnsafe () method limits that only the boot class loader will return the instance, that is, basically only rt. classes in jar can be used only), because DirectByteBuffer will also throw an OOM exception, but when an exception is thrown, there is no real request for memory allocation from the operating system, instead, it is learned through calculation that unallocation will throw. The true method for applying for allocation is unsafe. allocateMemory ().

/**
* VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
* @author zzm
*/
public class DirectMemoryOOM {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
unsafe.allocateMemory(_1MB);
}
}
}

Running result:

Exception in thread "main" java. lang. OutOfMemoryError

At sun. misc. Unsafe. allocateMemory (Native Method)

At org. fenixsoft. oom. DirectMemoryOOM. main (DirectMemoryOOM. java: 20)

 

 

Summary

So far, we have figured out how the memory in the virtual machine is divided, what areas, what code, and operations may cause OOM exceptions. Although Java has a garbage collection mechanism, OOM is still far away from us. In this chapter, we only know the causes of OOM exceptions in various regions, in the next chapter, we will look at the Java garbage collection mechanism's efforts to avoid OOM exceptions.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.