Vm memory model

The logical partition of virtual machine memory is shown in the figure above, which is divided into method area, heap, virtual machine stack, local method stack and program counter. The method area and heap data are shared by all threads, while the virtual machine stack, local method stack, and program counter data are thread isolated.

Program counter

  • The line number indicator of the bytecode executed by the current thread (which line of bytecode is executed by the current thread)
  • The only area that does not specify any outOfMemoryError cases in the Java Virtual Machine specification
  • If the thread is executing a Java method, this counter records the address of the virtual machine bytecode instruction being executed. If the Native method is being executed, this counter value should be null.

The virtual machine stack

The virtual machine Stack describes the threaded memory model of Java method execution: For each method execution, the Java VIRTUAL machine synchronously creates a Stack Frame [1] to store information about local variables, operand stacks, dynamic connections, method exits, and so on. The process of each method being called and executed corresponds to the process of a stack frame moving from the virtual machine stack to the virtual machine stack.

The local variable table is part of the virtual machine stack. The storage space of these data types in the local variable table is represented by local variable slots. 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.

In the HotSpot VIRTUAL machine, StackOverflowError is raised if the stack depth requested by the thread is greater than the virtual machine allows or the stack memory requested is greater than the virtual machine’s maximum stack memory.

Local method stack

  • This is very similar to the role played by the virtual machine stack, except that the virtual machine stack performs Java methods (that is, bytecode) services for the virtual machine, while the Native method stack serves Native methods used by the virtual machine.
  • Some virtual machines, such as the Sun HotSpot VIRTUAL machine, simply combine the local method stack with the virtual machine stack

The heap

The Java Virtual Machine Specification states that all object instances and arrays should be allocated on the heap. The Java heap is an area of memory managed by the garbage collector. The more detailed division of the Java heap depends on different garbage collectors. Let’s take a look at the division of the Java heap using the G1 collector as an example.

The heap is divided into two regions: the young generation and the old generation, depending on the object’s lifetime:

The young generation is divided into Eden zone and two Survivor zones. All newly created objects are in Eden zone. When Eden zone is full, minor GC will be triggered to copy the surviving objects in Eden zone to one Survivor zone. Surviving objects from another Survivor zone are also copied to this Survivor to ensure that one Survivor zone is always empty. In default Settings, Eden: from: to = 8:1:1.

The Old age stores objects that survived the minor GC after the Young zone was full. When the Eden zone is full, the objects are stored in the Survivor zone. If the Survivor zone still does not hold these objects, the GC collector stores them directly in the Old zone. If the object in the Survivor zone is Old enough, it is also placed directly in the Old zone. If the Old section is also Full, the Full GC is triggered to reclaim the entire heap memory.

The Perm section holds mostly Class objects, and garbage collection in the Perm section is also triggered by the Full GC.

Each generation uses n discrete regions of the same size. Each Region occupies a contiguous chunk of virtual memory (H in the figure below represents large objects) :

Methods area

Used to store information about classes that have been loaded by the virtual machine (the fully qualified name of the class accesses the properties and methods of the class), constants, static variables, code compiled by the just-in-time compiler, and so on.

The method area has different representations in different versions of VMS:

  1. In the HotSpot virtual machine prior to 1.8, the method area was implemented using persistent generations
  2. HotSpot in JDK 7 moves the pool of string constants, static variables, and so on out of the persistent generation and into the Java heap
  3. JDK 8 completely scrapped the concept of permanent generations and instead implemented Metaspace in local memory, moving all remaining content (mainly type information) from JDK 7 permanent generations into Metaspace.

Implement the memory model of the method area using persistent generation:

Implement the method area memory model with Metaspace:

The size of the permanent generation is determined by the JVM parameter MaxPermSize(-xx :MaxPermSize), which has a default size if not set. Once in the meta space, you should be fine as long as you don’t hit the upper limit of available memory for the process, such as the 4GB limit on 32-bit systems.

The use of persistent generation to implement method areas is abandoned because it makes Java applications more prone to memory overflow.

The Runtime Constant Pool is part of the method area. The Constant Pool Table is used to store various literals and symbolic references generated at compile time. This part of the Table is stored in the runtime Constant Pool of the method area after the Class is loaded.

In general, in addition to saving symbolic references described in Class files, direct references translated from symbolic references are also stored in the runtime constant pool.

Direct memory

Direct Memory (also known as out-of-heap Memory) is not part of the data area of the virtual machine, nor is it a Memory area defined in the Java Virtual Machine Specification. Direct Memory allocation is not limited by the size of the Java heap.

So here’s an example, NIO(New) was added in JDK 1.4 The Input/Output class introduces an I/O method based on channels and buffers. It can use Native libraries to allocate out-of-heap memory directly, and then reference this memory through a DirectByteBuffer object stored in the Java heap Line operations. This can significantly improve performance in some scenarios because it avoids copying data back and forth between the Java heap and Native heap.

public static void main(String[] args) throws IOException {
        File file = new File("");
        FileInputStream fileInputStream = new FileInputStream(file);

        // Request 100 bytes of off-heap memory
        ByteBuffer byteBuffer = ByteBuffer.allocate(100);
        FileChannel fileChannel = fileInputStream.getChannel();

        int len = 0;
        while((len = fileChannel.read(byteBuffer)) ! =1) {byte[] bytes = byteBuffer.array();
            System.out.write(bytes,0,len); byteBuffer.clear(); }}Copy the code

Out-of-heap memory is managed directly by the operating system (not the virtual machine). The result is to keep a small amount of in-heap memory to reduce the impact of garbage collection on the application.

Object and memory models

Object memory layout

In the HotSpot VIRTUAL machine, the storage layout of objects in the heap memory can be divided into three parts:

Object Header, Instance Data, and Padding.

Object head

The object header of the HotSpot VIRTUAL machine object contains two types of information:

  1. Mark Word (Mark field) : Store the runtime data of 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 in 32-bit and 64 bits in 64-bit virtual machines (without compression pointer enabled).
  2. Klass Point: A pointer to an object’s type metadata that the Java virtual machine uses to determine which class the object is an instance of.

If the object is a Java array, there must also be a piece of data in the object header to record the length of the array, because the virtual machine can determine the size of the Java object from the metadata information of ordinary Java objects, but if the length of the array is uncertain, there is no way to infer the size of the array from the information in the metadata.

The instance data

Class field information (including data inherited from the parent class)

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. The default allocation sequence of HotSpot VMS is Longs/Doubles, INTS, SHORTS /chars, Bytes/Booleans, and Oops (Ordinary Object) As you can see from the default allocation policy above, fields of the same width are always allocated together. Variables defined in the parent class will appear before the child class if this condition is met.

If the HotSpot VIRTUAL machine’s +XX:CompactFields parameter is true(the default is true), then narrower variables in the subclass are allowed to be inserted between the parent variables to save a little space.

Align fill data

The HotSpot VIRTUAL machine’s automatic memory management system requires that the object start address be an integer multiple of 8 bytes.

Object creation process

The object creation process is as follows:

  1. When the Java virtual machine reaches a bytecode new instruction, it first checks to see if the instruction’s arguments locate a symbolic reference to a class in the constant pool, and to see if the symbolic reference represents a class that has been loaded, parsed, and initialized. If not, the corresponding class loading process must be performed first.

  2. After the class load check passes, the virtual machine allocates memory for the new object in two ways: pointer collision and free list.

  3. After the memory allocation is complete, the virtual machine initializes the allocated memory space (but not the object header) to zero.

The Java virtual machine also makes necessary Settings on the Object, such as which class the Object is an instance of, how to find the metadata information about the class, the Object’s hashCode(which is actually deferred until the Object::hashCode() method is actually called), the Object’s GC generation age, and so on. This information is stored in the Object Header of the Object.

  1. Use constructors to initialize objects.

Object access location

There are two main ways to access objects: handle access and direct pointer access.

Handle access

If handle access is used, a chunk 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.

The biggest benefit of using handles for access is that reference stores a stable handle address and only changes the instance data pointer in the handle when the object is moved (a very common behavior in garbage collection). Reference itself does not need to be modified.

Direct pointer access

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.

The biggest benefit of using direct Pointers is that it is faster, it saves time for a pointer location, and since object access is very frequent in Java, this overhead can add up to a very significant execution cost.

Out of memory

Heap overflow

An OutOfMemoryError is the most common memory exceptions in practical application, the Java heap memory leak, “Java. Lang. OutOfMemoryError exception stack information will follow further prompt” Java heap space “.

The conventional approach is to first analyze the dumped heap Dump snapshot through a Memory image analysis tool, such as Eclipse Memory Analyzer. The first step is to check whether the object in Memory that causes OOM is necessary or not, that is, to determine whether there is a Memory Leak or Memory Overflow.

If it is a memory leak, you can further use the tool to look at the chain of references between the leaking object and GC Roots to find out what reference path the leaking object went through and what GC Roots it was associated with so that the garbage collector could not reclaim them, based on the type information of the leaking object and its GC Roots Roots references the chain of information and can generally pinpoint exactly where these objects were created to find the code that caused the memory leak

If it is not a memory leak, in other words, that objects in memory really must survive, you should check the Java virtual machine’s heap parameters (-Xmx and -xMS) Settings against the machine’s memory to see if there is room to adjust up. Then check whether there are some objects from the code life cycle is too long, hold the state time is too long, storage structure design is not reasonable and so on, try to reduce the memory consumption during the operation of the program.

Stack overflow

The HotSpot virtual machine throws StackOverflowError when new stack frame memory cannot be allocated, either because the thread is requesting a stack depth larger than the maximum allowed by the virtual machine or because the stack size is exceeding the limit.

You can set the memory occupied by the thread stack with -xss.

For different versions of Java virtual machines and operating systems, the minimum stack size may be limited, depending on the paging size of the operating system. For example, -xss128K works with JDK 6 on 32-bit Windows, but works with JDK 6 on 64-bit Windows In Linux, the minimum stack size can be 228K. If the minimum stack size is lower than this, the HotSpot virtual machine will start with the following message:

The Java thread stack size specified is too small. Specify at least 228k
Copy the code

The method area (permanent generation implementation) overflows

Method area overflow is mainly due to a large number of constants and dynamically generated classes. Using permanent generation to implement method area overflow, usually the following error occurs

java.lang.OutOfMemoryError: PermGen space
Copy the code

Direct memory overflow

The size of DirectMemory can be specified with the -xx :MaxDirectMemorySize parameter. If not specified, it defaults to the maximum Java heap size (specified by -xmx).

When the direct memory overflow occurs, the following error message is reported:

An obvious feature of memory overflow caused by direct memory is in the Heap There are no obvious exceptions to the Dump file, but if you find that the Dump file generated after a memory overflow is small and your program uses DirectMemory directly or indirectly (NIO is a typical indirect use), you may want to focus on examining the DirectMemory cause.