Daily sentence

When a man works to meet the light, the light will soon come to him. – xue-feng feng

The premise to review

Previous article has introduced the JVM memory structure, why write a article, think mainly shows in systematic way before the JVM structures and features, but the possible loopholes and a lack of content, so small make up to undertake article analyzes the JVM technology trip – the content of the memory layout area into the next phase of development, I hope we can fill in the gaps. Java virtual machine memory is basically the JVM runtime data area, and its architecture is shown below:

  • The method area and heap are data areas shared by all threads.
  • The virtual machine stack, local method stack, and program counter are thread-isolated data areas.

Introduction to Memory Structure

These data areas are described in detail below.

Program counter (no OOM)

A program counter is a small memory space that acts as an address value indicator of the bytecode being executed by the current thread. (But not the same as PC counters in computer system architecture, which are primarily address value indicators used at the machine code level of the instruction set.)

functions

  1. The bytecode parser works by changing the value of the program counter to select the address value of the next bytecode instruction to execute.

  2. The branch, loop, jump, exception processing (followed by the use of exception table: abnormal monitoring range and ExceptionHandler processor to realize the code instruction address value) and thread recovery and other basic functions are dependent on the program counter to complete.

  3. JVM multithreading is implemented by switching threads and allocating slices of processor execution time so that only one thread instruction is executed by one processor at any one time.

  4. If a thread is executing a Java method, the counter records the address of the virtual machine bytecode instruction that is executing.

  5. Therefore, in order to ensure that the thread switches back to the correct execution position, each thread needs a separate program counter, which is therefore thread private memory.

  6. A program counter is an area of memory in the Java virtual machine that does not have any out-of-memory OutOfMemoryError conditions specified.

If you are executing a Native Method (in short, a Native Method is a Java interface that calls non-Java code. The implementation of this method is implemented in non-Java languages, such as C. This feature is not unique to Java. Many other programming languages have this mechanism. In C++, for example, you can tell the C++ compiler to call a C function with extern “C”. The value of the counter is null /Undefined.

Java virtual machine stack

The Java virtual machine stack is also thread-private and has the same life cycle as a thread. The virtual stack describes the memory model of Java method execution: each method is executed with a stack frame created to hold information about local variables, operand stacks, dynamic connections, and method exits. Each method is called until the completion of the execution process, corresponding to a stack frame in the virtual machine from the stack to the stack process.

  • The local variable table of the Java virtual machine stack stores data of the eight Java basic types known to the compiler (Boolean, byte, CHAR, short, int, float, long, double), object reference(note not the object instance itself), and method return address retur NAddress (refers to the address of a bytecode instruction).

  • The local variable table space unit of the Java virtual machine stack is Slot, where 64-bit double and long types occupy two slots, and the remaining data types occupy only one Slot. The memory space required for the local variable table is allocated at compile time. When entering a method, how much local variable space the method needs to allocate in the frame is completely determined. The size of the local variable table does not change during the method run, and is determined by the max_locals field in the code property defined by the class bytecode.

  • There are two exceptions to the Java virtual machine stack: A StackOverflowError is raised if the stack depth requested by a thread is greater than the maximum depth allowed by the virtual machine; If the vm stack can be dynamically expanded, OutOfMemoryError will be thrown when sufficient memory cannot be allocated during the expansion. If the XSS value is smaller, StackOverflowError will be more likely to occur. Simply increasing the XSS value in order not to throw SFE will result in OOM.

Local method stack

The function of the local method stack is very similar to that of the Java virtual machine stack. The difference is that the Java virtual machine stack serves the execution of Java methods by the VIRTUAL machine, while the local method stack serves the Native methods (such as Native methods) of the operating system invoked by the virtual machine.

  • The Java Virtual Machine specification does not mandate the implementation or data structure of the local method stack, and the Sun HotSpot VIRTUAL machine directly blends the Java virtual machine stack with the local method stack.

  • Similar to the Java virtual machine stack, the local method stack also throws StackOverflowError and OutOfMemoryError.

Heap Heap

The heap is the largest area of memory managed by the Java Virtual machine. The Java heap is an area of memory that is shared by all threads. It is created when the Java Virtual machine is started and its sole purpose is to hold object instances. Almost all object instances (including arrays) are allocated memory in the heap.

  • Described in the Java virtual machine specification is: all the object instance and array on the heap allocation, but with the development of the JIT compiler and escape analysis technology mature gradually, stack allocation, replacement scalar optimization technology will lead to some subtle changes take place, make all objects are allocated on the heap also gradually become no longer an “absolute”.

  • The Java heap is the main area of garbage collector management. From the perspective of garbage collection, the Java heap can be initially subdivided into the new generation and the old generation because the garbage collector basically adopts the generational collection algorithm.

    • From the point of view of memory collection, the Java heap can be subdivided into: new generation and old generation; More detailed are Eden space, From Survivor space, To Survivor space, etc.

    • From the perspective of memory Allocation, the Java heap shared by threads may have multiple Thread private Allocation buffers (TLabs).

  • However, no matter how to partition, it has nothing to do with the storage content, no matter which area, the storage is still the object instance, the purpose of further partition is to better reclaim memory or faster allocation of memory.

The Java Virtual Machine specification states that the heap can be in a physically discontiguous memory space, as long as it is logically contiguous. The implementation can be either fixed size or dynamically extensible. OutOfMemoryError is thrown if there is no memory in the heap to complete the instance allocation and the heap size cannot be expanded. The Java heap can be in a physically discontinuous memory space, as long as it is logically contiguous, like our disk space. When implemented, it can be either fixed size or extensible, but most current virtual machines are implemented as extensible (controlled by the -xmx and -xms parameters).

Common parameters for heap Settings are as follows:

  • -Xmn: indicates the size of the new area
  • -Xms: indicates the initial heap size
  • -Xmx: indicates the maximum heap size. When Xms and Xmx are set the same, the heap cannot be automatically expanded.
  • -xx :NewSize=n: Sets the size of the young generation
  • -xx :NewRatio=n: Sets the ratio of the young generation to the old generation. For example, is 3, indicating that the ratio of the young generation to the old generation is 1:3, and the young generation accounts for 1/4 of the sum of the young generation and the old generation
  • -xx :SurvivorRatio=n: ratio of Eden zones to Survivor zones in young generations. Notice that there are two Survivor zones.

For example: XX:SurvivorRatio=3, indicating that the Eden area is three times the size of one Survivor area but there are two Survivor areas, then Eden :Survivor = 3:2, and one Survivor area accounts for 1/5 of the whole young generation.

  • -xx :MaxPermSize=n/ -xx :MaxMetaspace: Set the implementation size of the method area

Methods area

The method area, like the heap, is an area of memory shared by threads to store data such as class information, constants, static variables, just-in-time compiled code that has been loaded by the virtual machine. Although the Java Virtual Machine specification describes the method area as a logical part of the Heap, the method area has an alias, non-heap.

The Sun HotSpot VIRTUAL machine called the method area Permanent Generation, and the most important part of the method area was the run-time constant pool.

  1. In addition to the description of the Class version, fields, methods, interfaces, and other information, the Class constant pool is used to store various literal variables, symbolic references, direct references, and so on generated at compile time.

  2. This content is stored in the runtime constant pool in the method area after the class is loaded, and new constants can be stored in the constant pool at run time, such as the Intern () method of String (String constants are already stored in the heap after JDK7).

  3. When the intern method is called, if the constant pool already contains a String equal to this String Object (determined by equals(Object)), the String from the pool is returned. Otherwise, the String is added to the pool and a reference to the String is returned.

For JDK8 and later Hotspot virtual machines and other virtual machines (BEA JRockit, IBM J9, etc.) there is no concept of a permanent generation.

  • How you implement method areas is a virtual machine implementation detail and is not subject to the vm specification, but using persistent generations to implement method areas is not a good idea because it is more likely to run into memory overflow problems (persistent generations have -xx: MaxPermSize (1/4 of physical memory), J9 and JRockit should not be a problem as long as they do not touch the upper limit of available memory for processes, such as 4GB on 32-bit systems. And there are very few methods (such as String.Intern ()) that can cause different performance on different VMS for this reason.

  • Therefore, for HotSpot VIRTUAL machines, according to the official roadmap information, there is also a plan to abandon the permanent generation and gradually adopt Native Memory to implement the method area. (In JDK 1.7, HotSpot removed the string constant pool that was originally in the permanent generation, while in JDK1.8, There are no permanent generations at all, putting the method area directly into a local memory area (meta-space) that is not connected to the heap.

The method area and runtime constant pool also throw OutOfMemoryError when memory allocation cannot be met.

Direct memory

Direct memory is not part of the Runtime data area of the Java Virtual machine, nor is it defined in the Java Virtual Machine specification, but it is still used in Java development.

  • NIO(new I/O), introduced in JDK1.4, introduces a Channel – and buffer-based I/O approach that allocates out-of-heap memory directly using the operating system’s native method libraries.
  • A DirectByteBuffer object stored in the Java heap is then used as a reference to out-of-heap direct memory, avoiding copying between Java heap memory and local direct memory, which can significantly improve performance.

Although the direct memory is not directly affected by the Java VIRTUAL machine memory, if the total of the memory areas of the Java VIRTUAL machine exceeds the physical memory limit and the direct memory is insufficient, an OutOfMemoryError will be thrown during dynamic expansion. (Note also that while the JVM cannot dynamically reclaim out-of-heap memory, it can control the handling of references to handle variables and reclaim out-of-heap memory.)

Direct memory reclamation process

  • Direct memory is not JVM virtual machine memory space, but its garbage collection is also the responsibility of the JVM.
  • While garbage collection is in progress, the virtual machine will reclaim the direct memory, but the direct memory can not be found in the new generation, the old generation, when the space is insufficient to notify the collector garbage back. It can only wait until the old age is Full and then “incidentally” help it clean up the memory of obsolete objects.
  • Otherwise, you have to wait until an out-of-memory exception is thrown, catch first, and then yell “system.gc ()” in the catch block. If the virtual machine still doesn’t listen, there is still a lot of free memory in the heap and it has to throw an overflow exception. (OOM in metadata space)

Introduction to Abnormal Problems

The Java heap overflow

Java heap is used to store instance objects. As long as objects are continuously created and references are reachable between GC Roots and objects to avoid garbage collector collecting instance objects, OutOfMemoryError will occur after Full GC is generated when the number of objects reaches the maximum heap capacity.

To use the following Java virtual machine parameters:

  • -xms =10m :(minimum heap memory is 10MB),
  • -xmx =10m :(the maximum heap memory is 10MB, the minimum heap memory is the same as the maximum heap memory to avoid dynamic heap expansion).
  • – XX: + HeapDumpOnOutOfMemoryError: allows Java virtual machine in the event of a memory leak generated when the current heap memory snapshot for anomaly analysis.

Java virtual machine stack and local method stack overflow

Since Sun’s HotSpot virtual machine does not distinguish between Java virtual machine stacks and local method stacks, the -xoss parameter (to set the local method stack size) exists for the HotSpot virtual machine, but is effectively invalid, and the stack size can only be set by the -xSS parameter.

Since both StackOverflowError and OutOfMemoryError can occur on the Java virtual machine stack, two examples are used to illustrate both cases:

(1) Java virtual machine stack depth overflow (too deep recursive level)

The virtual machine throws StackOverflowError when the stack execution depth exceeds the threshold, either because the stack frame is too large or because the virtual machine stack size is too small. Use -xss128K to set the Java virtual machine stack size to 128KB.

(2) Java virtual machine stack memory overflow (too many threads created)

The maximum memory that can be created by a thread = physical memory – maximum heap memory – Maximum method area memory. In the case that the Java virtual machine stack memory is certain, the larger the memory occupied by a single thread, the smaller the number of threads that can be created. Therefore, it is easy to cause Java virtual machine stack memory overflow exceptions in multi-threaded conditions. Use the -xss2m parameter to set the memory size of the Java vm stack to 2MB

Runtime constant pool overflow (currently adjusted to heap overflow)

The runtime constant pool is part of the method area, the maximum and minimum memory are set to 10MB in size, and cannot be expanded because the permanent generation maximum and minimum memory are the same size.

The String intern() method checks if there is a String equal to this String in the constant pool, then returns the String in the constant pool for the reference address in the heap. Otherwise, add the String contained in the String to the heap and store the address value in the constant pool. And returns a reference to this String. So the String intern() method is especially good for demonstrating a run-time constant pool overflow.


public class RuntimeConstantPoolOOM{ 

    public static void main(String[] args){ 

    List<String> list = new ArrayList<String>(); 

        int i = 0; 

        while(true){ list.add(String.valueOf(i++).intern()); }}}Copy the code

An OutOfMemoryError was generated in the constant pool at runtime because no more constants could be added.

Method area overflow

The runtime constant pool is part of the method area, and they all belong to the persistent generation memory area in the HotSpot VIRTUAL machine.

Java’s reflection and dynamic proxy can generate classes dynamically. In addition, third-party CGLIB can directly manipulate bytecode, and can also generate classes dynamically. Experiments are demonstrated by CGLIB. Also use -xx :PermSize/ -xx :MetaSpaceSize=10m and -xx :MaxPermSize/ -xx :MaxMetaSpaceSize=10m to set the maximum and minimum memory size of the method area to 10MB. And because the maximum and minimum memory size of the permanent generation are the same, they cannot be expanded.

Example code is as follows:

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{ 
        returnproxy.invokeSuper(obj, args); }}); enhancer.create(); }}class OOMObject{}}Copy the code

After running for a period of time, the method area is out of memory and can no longer store the Class information for CGLIB creation, resulting in OutOfMemoryError.

Native direct memory overflow

-xx :MaxDirectMemorySize Can be used to set the available size of the native direct memory for a Java VM. If this parameter is not specified, it is the same size as the Java heap memory by default.

  • In the JDK, the Unsafe class can be retrieved by reflection (the Unsafe getUnsafe() method only returns an instance by starting the class loader Bootstrap) to operate directly on native direct memory.

  • Limit the maximum available native direct memory size to 10MB by using -xx :MaxDirectMemorySize=10M, for example:


public class DirectMemoryOOM{ 

    private static final int _1MB = 1024* 1024 * 1024; 

    publc 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 directly requests memory for the operating systemunsafe.allocateMemory(_1MB); }}}Copy the code

OutOfMemoryError is generated when 10MB of native direct memory is allocated light after running for some time and cannot be allocated direct memory.

conclusion

The program counter, virtual machine stack, and local method stack in the Java virtual machine memory structure are created and destroyed by a thread, so memory allocation and reclamation of these three areas are determined. The Java garbage collector focuses on the Java virtual machine’s heap and method area memory.