Deep understanding of Java Virtual Machine _ Chapter 2 _ Reading Notes and deep understanding of virtual machines
1. Contents of this chapter:
- Overview
- Data Area During Running
- Program counters
- Java Virtual Machine Stack
- Local method Stack
- Java heap
- Method Area
- Runtime constant pool
- Direct Memory
- HotSpot virtual machine object discovery
- Object Creation
- Object Memory Layout
- Object Access and positioning
- Practice: OutOfMemoryError exception
- Java Heap Overflow
- Virtual Machine stack and local method Stack Overflow
- Method Area and runtime constant pool overflow
- Local direct memory overflow
2. Details of this chapter:
2.1 Overview:
For C/C ++, memory management has the highest right. It not only has the "ownership" of each object, but also bears the Maintenance Responsibility for the beginning and end of every object's life.
For java, the right to control the memory is handed over to the java Virtual Machine. Instead of having to write the paired delete/free code for each new operation, it is not prone to memory leakage and overflow problems. However, in the event of Memory leakage and overflow problems, if you do not understand the VM memory running process, troubleshooting will be very difficult. The following figure shows the basic structure of the Java Virtual Machine.
2-1
2.2 Data Area During Running
Shows the data area when the Java virtual machine is running. Where,Virtual Machine stack, local method stack, and program counter are data zones with thread isolation. The local database interface, heap, execution engine, and method area are the areas shared by all threads.
2-2
2.2.1 program counter
The program counter is a small memory space and is the bytecode executed by the current thread.Row number indicator. It is used to select the line number command of the next executed bytecode. (Branches, loops, jumps, exception handling, thread recovery, etc. all rely on this counter to complete)
The multithreading of Java Virtual Machine is implemented by switching threads in turn and allocating the processor execution time.A single processor (a multi-core processor is just a kernel) can only process instructions in one thread at any definite moment. In order to restore the thread to the correct position after switching, each thread needs an independent program counter, and each thread is stored independently without affecting each other, we call this type of memory area a "thread-private" memory.
If the thread is executing a java method, the counter records the address of the Virtual Machine bytecode instruction being executed. If the Native method (local method) is being executed, this counter is blank (undefined ). This memory region is the only region in which OutOfMemoryError is not specified in the Java Virtual Machine specification.
2.2.2 Java Virtual Machine Stack
The Java Virtual Machine (Starks) Stack is also proprietary to threads, and its lifecycle is the same as that of threads.The VM stack describes the Memory Model of java method execution.: Each method creates a Stack frame (Stack Fram) during execution to store information such as the local variable table, operand Stack, dynamic link, and method exit.Each method is called until the process is completed, which corresponds to the process of putting a stack into the stack in the virtual machine to go out of the stack.
In the virtual machine StackLocal variable table, Stores various known during the compilation periodBasic Data Type(Boolean, byte, char, short, int, float, double ),Object Reference(Reference type, which is not the same as the object itself. It may be a reference pointer pointing to the starting address of the object, or it may point to a handle representing the object or other locations related to the object ),ReturnAddress type(Pointing to the address of a bytecode instruction ). Data of the 64-bit long and double types occupy two local variable spaces (slots), and the remaining data types only occupy one space.Memory space required for the local variable table is allocated during compilationWhen you enter a method, the size of the local variable space allocated in the frame must be completely determined. The size of the local variable table will not be changed during the method running.
Two exception handling conditions are defined in the Java Virtual Machine Stack: If the stack depth of thread requests is greater than the depth allowed by the virtual machine, an StackOverflowError exception will be thrown; if the Virtual Machine stack can be dynamically expanded (most virtual machines can be dynamically expanded), when the expansion fails to apply for sufficient memory, an OutOfMemoryError exception will be thrown.
2.2.3 Native Method Stack)
THE Native Method Stack plays a similar role as the Virtual Machine Stack. The only difference is that the virtual machine stack performs java (also known as bytecode) services for virtual machines, whileThe local method stack is the Native method service used by the virtual machine.
Some virtual machines directly combine the local method stack with the Virtual Machine stack. Like the Virtual Machine stack, the local method Stack also throws StackOverflowError and OutOfMemoryError exceptions.
(Note:Native Method: A Native Method is a java interface that calls non-java code. A Native Method is such a java Method: the implementation of this Method is implemented by a non-java language, such as C. This feature is not unique to java. Many other programming languages use this mechanism, for example, in C ++, you can use extern "C" to notify the C ++ compiler to call a C function. Sometimes a java application needs to interact with an environment outside java. This is the main reason for the existence of local methods. You can think about the situation that java needs to exchange information with some underlying systems, such as the operating system or some hardware. The local method is such a communication mechanism: it provides us with a very simple interface, and we do not need to understand the tedious details outside of java applications .)
2.2.4 Java Heap)
Generally, java heap is the largest memory managed by java virtual machines. A memory area shared by all threads in the java heap. It is created when the VM is started. The only purpose of this part of memory creation is to store object instances, where almost all object instances are allocated memory. The Java virtual machine specification is described as"All object instances and arrays must be allocated on the stack.".
Java Heap is the main area of the Garbage collector management, so it is often referred to as "GC Heap" (Garbage Collected Heap).
The java heap can be physically in a non-sequential memory space. It only needs to be logically continuous, just like our disk space. During implementation, it can be fixed or scalable. If instance allocation is not completed in the heap and the heap cannot be expanded, an OutOfMemoryError error will be thrown.
2.2.5 Method Area
The Method Area is the same as the Java heap. It is the memory Area shared by various threads, it is used to store data such as class information, constants, static variables, and Code Compiled by the real-time compiler that has been loaded by virtual machines. The java virtual machine specification describes the method area as a logical part of the Heap, but it has an alias "No-Heap" (non-Heap), which is used to distinguish it from the java Heap.
In addition to the java heap, the java Virtual Machine's method area does not require continuous memory and can be fixed or scalable, but can also choose not to implement garbage collection. Garbage collection is rare in this area, but it does not mean that the data enters the method area, it is equivalent to "always exist ".The main purpose of this region is to recycle the constant pool and unload the type.
When the method area cannot meet the memory allocation requirements, an OutOfMemoryError error is thrown.
2.2.6 runtime constant pool
The Runtime Constant Pool is part of the method area..Class FileIn addition to the class version, field, method, interface, and other description information, there is also a Constant Pool Table ), it is used to store various types of literal and symbolic references generated during the compilation period. This part of content will be stored in the runtime pool of the method area after the class is loaded.
The constant pool is part of the method area. Therefore, an OutOfMemoryError error is thrown when the Memory Pool cannot apply for a method.
2.2.7 Direct Memory
The direct memory is not a part of the VM running data, nor is it the memory area defined in the Java VM specification. To distinguish it, write it here.
Added in JDK1.4NIO (new input/output) class introduces an I/O Method Based on Channel and Buffer. It can use the Native function library to directly allocate off-heap memory.And then use a DirectByteBuffer object stored in the java heap as a reference to the memory.In this way, a DirectByteBuffer object stored in the java heap is used as a reference to this memory. This avoids copying data back and forth between java heap and native heap, thus improving performance.
2.3 HotSpot virtual machine object discovery
2.3.1 object Creation
The following describes the entire process of virtual machine object creation. Where,The VM allocates memory for new objects in two ways:: First, the java heap is absolutely regular. All used memory is put on one side, the idle memory is put on the other side, and a pointer is put in the middle as the indicator of the demarcation point, the allocated memory just points the pointer to the idle space and moves it to a distance equal to the object size. This allocation method is called"Pointer collision" (Bump the Point)Second, the memory in the java heap is not regular, and the used memory and idle memory are intertwined. The virtual machine must maintain a list and record which memory blocks are available, during allocation, a large enough space is found in the list and allocated to the object instance, and records in the list are updated. This allocation method is called"Free List ).The distribution method is determined by whether the java heap is regular, and whether the java heap is regular is determined by whether the garbage collector is compressed. In addition, the memory may be allocated to multiple objects during the process of dividing the available space. When the memory is allocated to object A, the pointer has not been modified yet, object B uses the original pointer to allocate memory at the same time. There are two solutions to solve this problem: solution 1: synchronous processing of memory space actions; solution 2: dividing memory allocation actions in different spaces by threads, that is, each Thread allocates a small block of memory in advance in the java heap, which is called the Local Thread Allocation Buffer (TLAB ).
2-3
2.3.2 memory layout of Objects
In the hotspot virtual machine, the layout of objects stored in the memory can be divided into three areas: object Header, Instance Data, and padding ).
HotSpot virtual machine object headerIncluding two parts of information,The first part is used to store the runtime data of the object.Such as HashCode, GC generational age, lock status mark, thread lock, thread ID, and timestamp.
Table 2-3-2 hot spot virtual machine object header Mark Word
Storage content |
Flag Space |
Status |
Object hash code, object generation age |
01 |
Unlocked |
Pointer to lock record |
00 |
Lightweight locking |
Pointer to the heavyweight lock |
10 |
Expansion (heavyweight lock) |
Null, no need to record information |
11 |
GC mark |
Biased towards thread ID, biased towards timestamp, object generational age |
01 |
Bias |
Another part of the object header is the type pointer.That is, the pointer to the class metadata of the object. The VM uses this pointer to determine the instance of the class of the object. If an object is a java array, a piece of data must be included in the object header to record the length of the array, because the virtual machine can determine the size of the java object through the metadata information of the common java object, however, the array size cannot be determined from the array metadata.
Instance dataIt is the valid information actually stored by the object and the various types of fields defined in the program code. Both inherited from the parent class and defined in the subclass must be recorded.
Alignment FillingIt does not necessarily exist. It has no special significance. It only plays a placeholder role. Because the Automatic Memory Management System of the HotSpot VM requires that the starting address of the object must be an integer multiple of 8 bytes. That is to say, the object size must be an 8-byte integer. Therefore, when the data part of the object instance is not aligned, it needs to be completed by alignment filling.
2.3.3 access and positioning of Objects
Objects are created to use objects. Our java program uses reference data on the stack to operate specific objects on the stack. Because the reference type specifies a reference pointing to an object in the Java virtual machine, it does not define how the reference should be used to locate and access the specific location of the object in the heap, therefore, the object access method depends on the Virtual Machine implementation. Current mainstreamObject AccessYou can use a handle or a direct pointer.
(1)Handle Access Object
If a handle is used for access, the java heap will divide a block of memory as the handle pool. The reference stores the handle address of the object, the handle contains the specific address information of the object instance data and type data. As shown in: (ps:A reference is a special smart pointer.When an application references memory blocks or objects managed by other systems (such as databases and operating systems), it must use a handle, which is referred to as a reference in C ++ ).
2-4
(2)Direct pointer access
If direct pointer access is used, you must consider how to place information about access type data in the layout of the java heap object. The object address is stored in reference, as shown in,
2-5
(2)Compare the advantages of the two access methods
Handle accessThe biggest benefit is that the reference stores a stable handle address. when an object is moved (garbage collection is a very common behavior for moving objects), it only changes the instance data pointer in the handle, the reference itself does not need to be modified.
Direct pointer accessThe biggest advantage is that the speed is faster and saves the time overhead of a pointer location. Because object access is very frequent in java, this overhead is also a very considerable execution cost after it is accumulated.
Memory leakage: memory is dynamically allocated to some temporary objects in the program, but the objects are not recycled by GC, and they always occupy the memory. That is, the allocated object is reachable but useless.
Author: yeiqing000
Link: http://www.imooc.com/article/15379
Source: MOOC
(Annotation:Memory leakage: indicates that the program dynamically allocates memory to some temporary objects. However, the objects are not recycled by GC, and they always occupy the memory, that is, the allocated objects are reachable but useless;
Memory overflow: an error that occurs when the program is running and cannot be applied for enough memory;)
2.4 practice: OutOfMemoryError (OOM exception)
2.4.1 java Heap Overflow
Java heap is used to store object instances. As long as you constantly create objects and ensure that there is a reachable path between GC Roots and objects, the garbage collection mechanism does not clear these objects, A Memory exception occurs when the number reaches the maximum heap capacity limit.
The code in the code list limits the java heap size to 20 MB and cannot be extended (setting the minimum-Xms parameter of the heap to the maximum-Xmx parameter can avoid automatic heap extension ), the-XX: + HeapDumpOnOutOfMemoryError parameter allows the VM to Dump the current memory heap Dump snapshot when a memory overflow exception occurs.
/**
*VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
*
*/
public class HeapOOM{ static class OOMObject{}; public static void main(String[] args){ List<OOMObject> list = new ArrayList<OOMObject>(); while(ture) { list.add(new OOMObject()); } }}
Running result:
java.lang.OutOfMemoryError:java Heap SpaceDumping heap to java_pid3404.hprof ...Heap dump file created [22045981 bytes in 0.663 secs]
OOM exceptions in java heap memory are common memory overflow exceptions in actual applications. WhenWhen the java Heap memory overflow occurs, the exception stack information "java. lang. OutOfMemoryError" will be followed by the prompt "java Heap Space ".
2.4.2 Java Virtual Machine stack and local method Stack Overflow
HotSpot virtual machines do not distinguish Virtual Machine stacks from local method stacks. Therefore, for HotSpot, although the-Xoss parameter (local method stack size) exists, it is actually invalid, the stack capacity is only set by the-Xss parameter. Two types of exceptions are described in Java virtual machine:
The code here tests the first point;
/** *VM Args: -Xss128k * */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:2402Exception in thread "main" java.lang.StackOverflowError ......
The results show that, in a single thread, StackOverflowError is thrown when the memory is not distributed because the stack frame is too large or the VM stack capacity is too small.
If the created thread is not limited to a single thread, a memory overflow exception can be generated by continuously establishing multiple threads, as shown in the following code list:
/*** VM Args:-Xss2M (you can set a larger value at this time )**/
Public class javaVMStackOOM {private void dontStop () {while (true ){}}
Public void stackLeakByThread () {while (ture) {Thread thread = new Thread (new Runnable () {@ override public void run () {dontStop () ;}}); thread. start ();} public static void main (String [] args) throws Throwable {JavaVMStackOOM = new JavaVMStackOOM (); oom. stackLeakByThread ();}
}
The running result is:
Exception in thread "main" java.lang.OutOfMemoryError:unable to create new native thread.
The memory overflow (OutOfMemoryError) produced by multithreading does not have any relationship with the size of the stack space. To be precise, in this case, the larger the memory allocated to the stack of each thread, instead, it is more likely to cause memory overflow exceptions (because the larger the stack memory, the smaller the java heap memory, the fewer threads that can be allocated, and the more likely the memory overflow OutOfMemoryError ).Stack Overflow is directly related to the memory size allocated to the stack.
Multi-thread-caused memory overflow. If you cannot reduce the number of threads or replace 64-bit virtual machines, you can only reduce the maximum heap and stack capacity in exchange for more threads.Because the stack capacity is reduced, the java heap can get more memory and allocate more threads. In addition, the maximum heap is reduced, the more heap space remaining on the java stack, the more threads can be created. (See figure 2-1/Figure 2-2 ).
2.4.3 method zone and runtime constant pool overflow
Because the runtime frequent volume pool is part of the method area, the overflow tests in these two areas are put together.
String. intern () is a native method (written in C/C ++). Its function is: if the String constant pool already contains a String equal to this String object, returns the String object representing the String in the pool. Otherwise, the String contained in the String object is added to the constant pool and a reference to the String object is returned.
Memory overflow exception caused by the frequent running pool: (JDK1.6)
/*** VM Args:-XX: PermSize = 10 M-XX: MaxPermSize = 10 M **/public class RuntimeConstantPoolOOM {public static void main (String [] args) {List <String> list = new ArrayList <String> (); // use List to keep reference to the constant pool, avoiding Full GC to reclaim the constant pool.
Int I = 0; // The Permsize of 10 MB is sufficient to generate OOM in the integer Range.
While (ture ){
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
As you can see from the running results, the prompt message followed by OutOfMemoryError is "PermGen space", indicating that the runtime frequent pool is part of the method zone.
String. intern () returns the referenced test :( JDK1.7)
Public class RuntimeConstantPoolOOM {public static void main (String [] args) {public void main (String [] args) {String str1 = new StringBuilder ("computer "). append ("software "). toString (); System. out. println (str2.intern () = str1); String str2 = new StringBuilder ("ja "). append ("va "). toString (); System. out. println (str2.intern () = str2 );}}}
In JDK1.6, two false values are returned, while in JDK1.7, a true value and a false value are returned. The reason for the difference is that in JDK1.6, the intern () method will copy the instance of the first character encountered to the permanent generation, and the return will also be a reference of the instance in the permanent generation, the string instance created by StringBuilder is on the java stack. Therefore, if it is not the same reference, false is returned. The intern () Implementation in JDK1.7 does not copy instances, but only records the instance reference for the first time in the constant pool. Therefore, the reference returned by intern () is the same as the string created by StringBuilder.
2.4.4 local direct memory overflow
The DirectMemory capacity can be specified through-XX: MaxDirectMemorySize. If this parameter is not specified, the default value is the same as the java stack maximum value (-Xmx.
Use unsafe to allocate local memory:
/** *VM Args: -Xmx20M -xx:MaxDirectMemorySize = 10M * */public class DirectMemoryOOM { private static final int_1MB = 1024*1024; public static void main(String[] args) throws Exception { Filed unsafeFiled =Unsafe.class.getDeclaredFields () [0]; unsafeField.setAccessible(ture); Unsafe unsafe = (Unsafe) unsafeFiled.get(null); while(ture){ unsafe.allocateMemory (_1MB); } }
}
Running result:
Exception in thread "main" java.langOutOfMemoryError
... ..
The above code goes beyond the DirectByteBuffer class and gets the unsafe instance through reflection for memory allocation. Although the use of DirectByteBuffer to allocate memory also throws a Memory exception overflow exception, it does not apply to allocate memory in the operating system when it throws an exception. Instead, it learns through computing that the memory cannot meet the requirement (cannot be allocated ), therefore, an exception is thrown manually,The method for applying for memory allocation is unsafe. allocateMemory ().
Memory overflow caused by DirectMemory. An obvious feature is that no obvious exception is seen in the HeapDump file. If the Dump file after memory overflow (OOM) is small, if the program directly or indirectly uses NIO, consider whether it is the cause.