Preface: I have read “Deep Understanding of Java Virtual Machine”, and sorted out the output according to my reading notes. I hope it will be helpful to you. Limited capacity may be some mistakes or omissions, I hope you forgive! At the same time also pay tribute to the author Zhou Zhiming predecessors, this book is worthy of the “JVM Bible”, write really good, recommend everyone to see the original book!


It is well known that the JVM has automatic memory management, and in the case of Java, there is no need for programmers to manage memory manually.

Runtime data area

During the execution of a Java program, the JVM divides the memory it manages into several different data regions. As shown in the figure below

Program counter

Q: What is it?

A: A program counter is a small memory space that is a line number indicator of the bytecode being executed by the current thread.

Q: What are the characteristics?

A: It is a “thread private” memory area. If the thread is executing a Java method, the counter records the address of the virtual machine bytecode instruction being executed. If it is a local method, the counter value is null. This memory region is the only one that does not specify any OutOfMemoryError cases.

Q: What does it do?

A: The bytecode interpreter works by changing the value of the program counter to select the next bytecode instruction to execute. So the program counter is an indicator of the program’s control flow, and all the basic functions of branching, looping, exception handling, jumping, and thread recovery depend on the program counter.

Q: Why is it thread private?

Answer: because the Java virtual machine of multithreading is through the thread switching in turn, allocate processor execution time, at any moment, a processor will only perform a thread in the instruction, in order to thread after switching to restore to the execution of the right position, so each thread has an independent program counter, their mutual influence.

Java virtual machine stack

Q: What is it?

A: The virtual machine stack is a thread-in-memory model for Java method execution that stores stack frames. As each method is executed, the Java virtual machine synchronously creates a stack frame to store information about local variables, operand stacks, dynamic connections, method exits, and so on. Each method called to the end of the execution process corresponds to a stack frame in the virtual machine stack from the stack to the stack process.

Q: What are the characteristics?

Answer: 1, the thread private 2, the life cycle is the same as the thread.

StackOverflowError is raised if the thread request stack depth is greater than the virtual machine allows.

4. If the Java virtual machine stack can be dynamically expanded, OutOfMemoryError will be raised if sufficient memory cannot be allocated during stack expansion.

Q: What does it do?

A: Store the stack frame created when executing the method

Q: What is stack frame?

A: Stack frames are an important fundamental data structure for method runtime.

Q: what is the local variable scale?

A: The local variable table stores various Java virtual machine basic data types (Boolean, byte, CHAR, short, int, float, long, double) and object references (reference type, which is not the same as the object itself) known at compile time. May be a reference pointer to the object’s starting address, a handle representing the object or other location associated with the object) and the returnAddress type (which points to the address of a bytecode instruction).

The storage space of these data types in the local variable table is represented by local variable slots, where 64-bit long and double data types occupy two variable slots and the rest occupy only one.

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 stack frame is completely determined, and the size of the local variable table does not change during the method run. (The “size” here refers to the number of variable slots, and how much memory the virtual machine really uses to implement a variable slot (such as 32 bits per slot, 64 bits per slot, or more) is entirely up to the individual virtual machine implementation.)

Local method stack

Q: What is it?

A: Store stack frames created when the local method is executed.

Q: What are the similarities and differences with the virtual machine stack?

A:

The same

The local stack also throws StackOverflowError and OutOfMemoryError, respectively, when the stack depth overflows or the stack extension fails.

2. The thread is private and has the same life cycle as the thread.

The difference between

1. The virtual machine stack performs Java methods (aka bytecode) services for the virtual machine, while the Native method stack serves Native methods used by the virtual machine.

2. The virtual machine specification does not enforce the language, usage, or data structure of methods in the local method stack, so specific virtual machines can implement it freely.

The Java heap

Q: What is it?

A: An area of memory used to hold object instances.

Q: What are the characteristics?

A: Thread sharing.

1. Thread sharing

2. The Java heap can be physically discontiguous, but logically it should be treated as contiguous, just as we use disk space to store files without requiring each file to be contiguous. But for large objects (typically groups of objects), most virtual machine implementations will most likely require contiguous memory space for simplicity of implementation and storage efficiency.

3. The Java heap can be implemented as either fixed size or extensible, but most current Java virtual machines are implemented as extensible (with the -xmx and -xMS parameters). The Java virtual machine will throw an OutOfMemoryError if there is no memory in the Java heap to complete the instance allocation and the heap can no longer be extended.

Methods area

Q: What is it?

A: An area of memory used to store data such as type information that has been loaded by the virtual machine, constants, static variables, just-in-time compiler compiled code caches, and so on.

Q: Method area = permanent generation?

A: wrong. The two are not equivalent because it was only the previous HotSpot VIRTUAL machine design team that chose to extend the generational design of the collector to the method area, using persistent generation to implement the method area.

Q: What are the characteristics?

A: Thread sharing.

Run-time constant pool

Q: What is it?

A: It is part of the method area. The constant pool table is placed in the constant pool of the method area. The constant pool table is used to hold the various literal and symbolic references generated by the compiler.

Q: What are the characteristics?

A: The runtime constant pool is dynamic. It is not necessary to preset the contents of the constant pool in the class file to enter the runtime constant pool in the method area. New constants can be added to the pool at runtime. An OutOfMemoryError is raised when the constant pool can no longer allocate memory.

HotSpot VIRTUAL machine object

Object creation

1. When the virtual machine reaches a bytecode new instruction, it first checks whether the instruction’s argument can locate a symbolic reference to a class in the constant pool, and whether the symbolic reference represents a class that has been loaded, parsed, and initialized. If not, the corresponding class loading process is performed first.

2. After the class loading check, the virtual machine allocates memory for the object. The task of allocating memory is essentially the same as dividing a certain size of memory from the Java heap.

3. After memory allocation is complete, the VM must initialize the allocated memory space (excluding object headers) to zero. This ensures that the instance fields of the object can be used directly in Java code without assigning initial values, enabling the program to access the zero values corresponding to the data types of these fields.

4. The virtual machine makes the necessary Settings for the object, such as which class instance the object is, how to find the metadata information of the class, the hash code of the object, the GC generation age of the object, and so on. Store this information in the Object Header of the Object. The object header can be set differently depending on the VM running status, for example, whether biased locking is enabled.

After the above steps are complete, a new object has been created from the virtual machine’s perspective. But from the program’s point of view, the creation of the object is just beginning, because the constructor hasn’t been executed, the init method in the Class file hasn’t been executed, and all the fields are zero by default. Additional resources and state information required by the object have not been constructed as intended. In general, the new instruction is followed by the init method, which initializes the object as the programmer wishes so that a usable object can be fully constructed.

Q: Is memory allocated to objects from the heap?

Answer: There are two cases.

  • The memory in the heap is absolutely neat

Because memory is organized, used memory is placed on one side, free memory is placed on the other, and a pointer is placed in the middle as an indicator of the dividing point. The allocated memory simply moves that pointer to free space by an equal amount to the size of the object. This allocation is called a “Bump The Pointer.”

  • The memory in the heap is not tidy

This kind of situation has been used memory and free memory staggered together, that is simply no way pointer collision, the virtual machine, you must maintain a list of records on which memory blocks are available, at the time of distribution from the list to find a large enough space division to the object instance, and update the list of records, This type of allocation is called a Free List.

Q: How does a virtual machine determine whether the heap is clean?

A: It depends on whether the garbage collector has space compression collation (Comp Act) capability. When using Serial, ParNew and other collectors with compression and collation process, the system uses the allocation algorithm is pointer collision, which is simple and efficient; And when using CMS based cleanup

(Sweep) algorithm collector, theoretically can only use a more complex free list to allocate memory.

Q: Is object creation in a virtual machine thread-safe?

A: No, it is possible that object A is allocating memory and object B uses the original pointer to allocate memory at the same time before the pointer has been modified.

Q: How do I solve the thread-safe problem of creating objects?

A: There are two options.

  • Synchronizes the action of allocating memory space

The CENTRAL Authentication Service (CAS) configuration fails to retry to ensure atomicity of update operations

  • The action of allocating memory is divided into different Spaces by thread

Each Thread preallocates a small chunk of memory in the Java heap, called the Thread Local Allocation Buffer (TLAB). If the Thread wants to allocate memory, it allocates it to the Thread’s Local Buffer. Synchronization locking is only required when a new cache is allocated. The -xx :+/ -usetlab parameter is used to determine whether the VM uses TLAB.

Object memory layout

In the HotSpot VIRTUAL machine, the storage layout of objects in the heap memory can be divided into three parts: object headers, instance data, and aligned padding.

Object head

The object header contains two types of information.

The first type is the runtime data used to store the object itself, such as HashCode, GC generation age, lock status flag, thread held lock, bias thread ID, bias timestamp, etc. The length of this data is 32 bits and 64 bits in 32-bit and 64-bit virtual machines (without compression pointer enabled). It’s officially called the “Mark Word.”

The amount of runtime data an object needs to store exceeds the maximum 32 – and 64-bit Bitmap structures can record. However, the information in the object header is an additional storage cost independent of the data defined by the object itself. Considering the space efficiency of the virtual machine, Mark Word is designed as a data structure with dynamic definition. In order to store as much data as possible in a very small space, reuse their own storage space according to the state of the object. For example, in a 32-bit HotSpot VIRTUAL machine, 25 of the 32 bits of Mark Word storage space are used to store object hash codes, 4 bits are used to store object generation age, 2 bits are used to store lock flag bits, and 1 bit is fixed at 0 if the object is not locked by a synchronization lock

The contents of objects stored in other states (lightweight lock, heavyweight lock, GC mark, biased) are shown in the following table.

The second type is a type pointer, which is a pointer to an object’s type metadata that the Java virtual machine uses to determine which class the object is an instance of. Not all virtual machine implementations must keep type Pointers on object data; in other words, finding metadata information about an object does not have to go through the object itself. In addition, if the object is a Java array, it must also be in the head of an object has a piece of data is used to record the length of the array, because the virtual machine can be through ordinary Java object metadata information to determine the size of the Java object, but is not sure if the length of the array, will not be able to pass the information in the metadata deduce the size of the array.

The instance data

The instance data part is the valid information that the object actually stores, that is, the contents of the various types of fields that we define in the program code, whether inherited from a parent class or defined in a subclass, must be recorded. The storage order of this part is affected by the virtual machine allocation policy parameter (-xx :FieldsAllocationStyle parameter) and the order in which the fields are defined in the Java source code.

Alignment filling

Alignment padding does not necessarily exist and has no special meaning. It simply acts as a placeholder. Since the HotSpot VIRTUAL machine’s automatic memory management system requires that the object’s starting address be an integer multiple of 8 bytes, in other words, any object’s size must be an integer multiple of 8 bytes. The object header has been carefully designed to be a multiple (1 or 2) of exactly 8 bytes, so if the object instance data part is not aligned, it needs to be filled out by alignment.

Object access location

Once we’ve created the object, how do we use it? The program uses reference data on the stack to manipulate specific objects on the heap. Due to reference types in the Java virtual machine specification only it is a pointer to the object of reference, there is no definition of the reference should through what way to localization, the location of the access to the heap object, so the object access method is implemented by the virtual machine, the mainstream way of access are mainly using two kinds of handle and direct Pointers:

  • If handle access is used, a block of memory may be allocated to the Java heap as a handle pool. Reference stores the handle address of the object, and the handle contains the specific address information of the instance data and type data of the object, as shown in the following figure.

  • If direct pointer access is used, the memory layout of objects in the Java heap must consider how to place the information related to the access type data. The direct stored in reference is the address of the object. If only the object itself is accessed, there is no need for the overhead of an additional indirect access, as shown in the figure below.

Using direct pointer to access the biggest benefit is faster and it saved a pointer positioning time overhead, because the object access in Java is very frequent, so this is also a kind of overhead adds up very considerable execution cost, in terms of the HotSpot, it mainly use the second way to object access (there are exceptions, There is also an extra forward if the Shenandoah collector is used), but across the software development spectrum, it is common to use handles for access in a variety of languages and frameworks.

Heap overflow troubleshooting

Java heap memory overflow

An overview of the

In addition to program counters, outofMemoryErrors can occur in several other run-time areas of virtual machine memory, as described in the Java Virtual Machine specification

The Java heap overflow

  • The Java heap is used to store object instances, and as long as you keep creating objects and ensure that there is a reachable path between GC Roots and the created objects to avoid garbage collection, overflow exceptions will occur after the number of objects reaches the heap’s capacity limit.
  • OOM anomalies in Java heap memory is common memory leak in actual situation, when there is a Java heap memory leak, the exception stack information: Java. Lang. OutOfMemoryError: Java heap space

code

Set vm startup parameters

  • The Xms parameter is set to the same as the -xmx parameter to avoid automatic heap expansion
  • XX: + HeapDumpOnOutOfMemoryError parameters can make the virtual machine in the event of a memory Dump out when the current memory heap Dump snapshot for later analysis
package com.java.one;
 
import java.util.ArrayList;
import java.util.List;
 
/ Java heap overflow * * * * Args VM: - Xms20M - Xmx20M - XX: + HeapDumpOnOutOfMemoryError * * /
public class HeapOOM {
  static class OOMObjec {}public static void main(String[] args) {
    List<OOMObjec> list = new ArrayList<>();
    while (true) {
      list.add(newOOMObjec()); }}}Copy the code

Solve abnormal

  • View the stack information and resolve the problem based on your experience
  • Resolve general exceptions with memory image analysis tools

Dump snapshots are analyzed using a Memory image analysis tool (such as Eclipse Memory Analyser) The key is to determine whether the object in Memory is necessary — that is, whether it is a Memory Leak or a Memory Overflow.

1. Memory leak – Indicates that an object cannot release the allocated memory space after applying for it

If there is a memory leak, the tool can further look at the reference chain of the object to GC Roots to see what path the leaking objects took to associate with GC Roots and cause the garbage collector to fail to reclaim them automatically. With the type information of the leaking object and the GC Roots reference chain information, the location of the leaking code can be more accurately located.

2. Memory overflow – Indicates that the object does not have enough memory space when applying for memory, and OOM appears

If there is no leak, in other words, objects in memory must still be alive:

  • You should check the virtual machine’s heap parameter Settings (-xMX vs. -xMS) to see if the Settings are too small (compared to the machine’s physical memory)
  • Code to check whether there is some object life cycle is too long, hold the state for too long, try to reduce the memory consumption of the program runtime

The virtual machine stack and the local method stack overflow

An overview of the

The HotSpot VIRTUAL machine directly blends the virtual machine stack with the local method stack, so for HotSpot, the -xoss parameter (to set the local method stack size) exists but is actually invalid, the stack size is only set by the -xSS parameter StackOverflowError

StackOverflowError is thrown if the stack depth requested by the thread is greater than the maximum depth allowed by the virtual machine

package com.java.one;
​
/** * StackOverflowErroe is caused by a stack depth greater than the maximum allowed by the VIRTUAL machine * for example, the single thread * VM Args: -xss128K (-xSS virtual machine stack) ** /
public class JavaVMStackSOF {
    private int stackLength = 1;
​
    public void stackLeak (a) {
        stackLength++;
        stackLeak();
    }
​
    public static void main(String[] args) {
        JavaVMStackSOF javaVMStackSOF = new JavaVMStackSOF();
        try {
            javaVMStackSOF.stackLeak();
        } finally {
            System.out.println("Stack depth stackLength:"+ javaVMStackSOF.stackLength); }}}Copy the code

Print abnormal information:

Stack depth stackLength: 997 Exceptionin thread "main"java.lang.StackOverflowError at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13) at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14) at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14) at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14) at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14) at Com. Java. One. JavaVMStackSOF. StackLeak (JavaVMStackSOF. Java: 14)...Copy the code

In a single thread, the virtual machine throws StackOverflowError when memory cannot be allocated, either because the stack frame is too large or because the virtual machine stack size is too small (Xss is 128K here)

OutOfMemoryError

In other words, there is a limit to the size of the operating system’s memory. The more memory allocated by the stack for each thread, the fewer threads can be created. Operating system allocated memory =Xmx (maximum heap size) +MaxPermSize (maximum method size) + program counter consumed memory + VM process consumed memory + VM stack and local method stack consumed memory

package com.java.one;
​
/** * VM Args: -xss2m (vm stack size Xss can be set to a larger number of threads) * OS allocated memory =Xmx (maximum heap size) +MaxPermSize (maximum method size) + program counter consumption memory + VM process consumption memory + VM stack (local method stack) consumption memory * */
public class JavaVMStackOOM {
    private void dontStop (a) {
        while (true) {}}public void stackLeakByThread (a) {
        while (true) {
            // Create a thread
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run(a) { dontStop(); }});// Start the threadthread.start(); }}public static void main(String[] args) {
        JavaVMStackOOM javaVMStackOOM = newJavaVMStackOOM(); javaVMStackOOM.stackLeakByThread(); }}Copy the code

Setting up multiple threads leads to memory overflow, and without reducing threads or replacing 64-bit virtual machines, you have to reduce the maximum heap size and reduce the stack size in exchange for more threads

Method area and runtime constant pool overflow

An overview of the

The run-time constant pool is part of the method area (permanent generation) and the parameters -xx :PermSize and -xx :MaxPermSize limit the size of the method area, thereby indirectly limiting the size of the constant pool.

  • In JDK6 and previous versions, the string constant pool is in the permanent generation
  • HotSpot in the released JDK7 has removed the string constant pool from the persistent generation.

Memory overflow exception caused by run-time constant pool

Intern is a Native method that does:

  • If the String constant pool already contains a String equal to a String, return a String for that String in the constant pool
  • If not, the String contained in this String is added to the constant pool and a reference to this String is returned.
package com.java.one;
​
import java.util.ArrayList;
import java.util.List;
​
* VM Args: -xx :PermSize=10M -XX:MaxPermSize=20M ** /
public class RuntimeConstantPoolOOM {
​
    public static void main(String[] args) {
        // Use List to keep references to constant pools, avoiding Full GC's behavior of reclaiming constant pools
        List<String> list = new ArrayList<>();
        int i = 0;
        while (true) { list.add(String.valueOf(i++).intern()); }}}Copy the code
  • In JDK6 or earlier, memory overflow OOM indicates that the runtime constant pool is part of the method area
  • For JDK7 and beyond, without OOM, the while loop will continue forever

String.intern() returns the referenced test

package com.java.one;
​
/** * string.intern () returns the referenced test ** /
public class RuntimeConstantStringIntern {
​
    public static void main(String[] args) {
        String str1 = new StringBuilder("Computer").append("Software").toString();
        System.out.println(str1.intern() == str1);
​
        String str2 = new StringBuilder("ja").append("va").toString(); System.out.println(str2.intern() == str2); }}Copy the code

In JDK8, string.intern () returns a reference to the first occurrence of an instance in the String constant pool. The String “computer software” is the first occurrence, so returns true, whereas “Java” has occurred before and is not the same as the “Java” String reference now created. Returns false.

CGLib causes the method area to run out of memory

package com.java.one;
​
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
​
* VM Args: -xx :PermSize=10M -XX:MaxPermSize=10M ** /
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) {
                    returnproxy.invokeSuper(obj, args); }}); enhancer.create(); }}static class OOMObject {}}Copy the code