All Java developers are likely to encounter this confusion? How much space should I set for heap memory? What part of the runtime data does an OutOfMemoryError exception involve? How to solve it? In fact, if you often solve server performance problems, these problems will become very common. Understanding JVM memory is also a way to quickly understand which area of memory is failing when server performance problems occur, so that you can quickly resolve production failures.

Let’s take a look at a diagram that clearly illustrates the layout of the JVM memory structure.

The JVM memory structure has three main blocks: heap memory, method area, and stack. Heap memory is the largest chunk of the JVM, consisting of the young generation and the old generation. The young generation memory is divided into three parts: Eden space, From Survivor space, and To Survivor space. By default, the young generation is allocated in a 8:1:1 ratio.

The method area stores class information, constants, static variables, and other data. It is shared by threads. To distinguish it from the Java Heap, the method area is also nicknamed non-heap. The stack is divided into Java virtual machine stack and local method stack mainly used for method execution.

How to control the memory size of each region with parameters in a diagram

Control parameters

  • -Xms Sets the minimum size of the heap.

  • -Xmx Sets the maximum size of the heap.

  • -xx :NewSize Sets the minimum space size of the new generation.

  • -xx :MaxNewSize Sets the maximum space size of the new generation.

  • -xx :PermSize Sets the minimum space size of the permanent generation.

  • -xx :MaxPermSize Sets the maximum space of the permanent generation.

  • -Xss sets the stack size for each thread.

There is no direct setting of the old age parameters, but you can set the heap size and the new generation space size two parameters to indirectly control.

Old age space size = heap space size – young generation large space size

Look again at the relationship between the JVM and system calls from a higher dimension

Method areas and pairs are memory areas shared by all threads; The Java stack, native method stack, and programmer counter are areas of memory that are run private to the thread.

Let’s go into more detail about what each region does

Java Heap

For most applications, the Java Heap is the largest chunk of memory managed by the Java virtual machine. The Java heap is an area of memory that is shared by all threads and is created when the virtual machine is started. The sole purpose of this memory area is to hold object instances, and almost all object instances are allocated memory here.

The Java heap is the primary area managed by the garbage collector and is often referred to as the “GC heap”. 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.

According to the Java Virtual Machine specification, 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 -xmx and -xMS).

OutOfMemoryError is thrown if there is no memory in the heap to complete the instance allocation and the heap can no longer be extended.

Method Area

The Method Area, like the Java heap, is an Area of memory shared by each thread. ** It is used to store information about classes that have been loaded by the virtual machine, constants, static variables, code compiled by the just-in-time compiler, and so on. ** Although the Java Virtual Machine specification describes the method area as a logical part of the Heap, it has an alias called non-heap, which is supposed to distinguish it from the Java Heap.

For developers who are used to developing and deploying applications on the HotSpot VIRTUAL machine, many prefer to refer to the method area as “Permanent Generation”, which is essentially not equivalent, simply because the HotSpot Virtual machine design team chose to extend GC Generation collection to the method area. Or to implement method sections using persistent generation.

The Java Virtual Machine specification is very relaxed about this area, in addition to the fact that, like the Java heap, it does not require contiguous memory and has the option of either fixed size or scalability, and optionally does not implement garbage collection. Garbage collection is relatively rare in this area, but it is not as “permanent” as the name of the permanent generation that data enters the method area. The target of memory reclamation in this area is mainly for constant pool reclamation and type unloading. Generally speaking, the “performance” of the reclamation in this area is not satisfactory, especially for type unloading, but the reclamation in this part of the area is indeed necessary.

According to the Java Virtual Machine specification, OutOfMemoryError is thrown when the method area cannot meet memory allocation requirements.

Method regions are sometimes called PermGen.

All objects are stored in heap memory for the entire runtime after instantiation. The heap memory is divided into different parts: Eden, Survivor, and Old Generation Space.

Methods are executed with threads. Local variables and references of primitive types are stored in the thread stack. Objects that reference associations, such as strings, are stored in the heap. To understand the above statement, let’s look at an example:

import java.text.SimpleDateFormat; import java.util.Date; import org.apache.log4j.Logger; public class HelloWorld { private static Logger LOGGER = Logger.getLogger(HelloWorld.class.getName()); public void sayHello(String message) { SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.YYYY"); String today = formatter.format(new Date()); LOGGER.info(today + ": " + message); }}Copy the code

The data of this program is stored in memory as follows:

The JConsole tool allows you to view information about running Java programs such as Eclipse: heap memory allocation, number of threads, and number of classes loaded;

Program Counter Register

The Program Counter Register is a small memory space that acts as a line number indicator of the bytecode being executed by the current thread. In the concept of virtual machine model (just the conceptual model, all kinds of virtual machine may be through some of the more efficient way to achieve), bytecode interpreter to work is by changing the counter value to select a need to be performed under the bytecode instruction, branches, loops, jumps, exception handling, thread to restore the basic function such as all need to rely on the counter.

Because multithreading in the Java VIRTUAL machine is implemented by the way threads alternate and allocate processor execution time, at any given moment, one processor (or kernel for multi-core processors) will execute instructions in only one thread. Therefore, in order to restore the thread to the correct execution position after switching, each thread needs to have an independent program counter. Counters between threads do not affect each other and are stored independently. We call this kind of memory area “thread private” memory.

If the thread is executing a Java method, this counter records the address of the virtual machine bytecode instruction being executed. If the Natvie method is being executed, this counter value is null (Undefined).

This memory region is the only one where the Java Virtual Machine specification does not specify any OutOfMemoryError cases.

JVM Stacks

Like program counters, the Java Virtual Machine Stack is thread-private and has the same lifetime as a thread. The virtual machine Stack describes the memory model of Java method execution: ** Each method execution creates a Stack Frame to store information about local variables, operation stacks, dynamic links, method exits, etc. Each method is called until the execution is complete, corresponding to the process of a stack frame in the virtual machine stack from the stack to the stack.

The local variable table stores various basic data types known at compile time (Boolean, byte, CHAR, short, int, float, long, double), object references (reference type, which is not equivalent to the object itself, depending on the implementation of different virtual machines. It may be a reference pointer to the object’s starting address, a handle to the object or some other location associated with the object, and the returnAddress type (which points to the address of a bytecode instruction).

64-bit long and double data occupy two local 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 frame is completely determined, and the size of the local variable table does not change during the method run.

In the Java Virtual Machine specification, two exceptions are specified for this area: a StackOverflowError is thrown if the stack depth of a thread request is greater than the depth allowed by the virtual machine; If the virtual stack can scale dynamically (and most Java virtual machines currently do, although the Java Virtual Machine specification also allows fixed-length virtual stacks), an OutOfMemoryError will be thrown when sufficient memory cannot be allocated while scaling.

Native Method Stacks

The Native Method stack is similar to the virtual machine stack, except that the virtual machine stack executes Java methods (i.e. bytecode) for the virtual machine, whereas the ** Native Method stack services the Native methods used by the virtual machine. ** The virtual machine specification does not mandate the language, usage, or data structure of methods in the local method stack, so specific virtual machines are free to implement it. There are even virtual machines (such as the Sun HotSpot VIRTUAL machine) that simply merge the local method stack with the virtual machine stack. Like the virtual stack, the local method stack area throws StackOverflowError and OutOfMemoryError exceptions.

Where is the OutOfMemoryError

A clear understanding of the memory structure also helps to understand the different OutOfMemoryErrors:

The Exception in the thread "main" : Java. Lang. OutOfMemoryError: Java heap spaceCopy the code

Cause: Objects cannot be allocated to heap memory

The Exception in the thread "main" : Java. Lang. OutOfMemoryError: PermGen spaceCopy the code

Cause: Classes or methods cannot be loaded into older generations. It can occur when an application loads many classes, such as libraries that reference many third parties.

The Exception in the thread "main" : Java. Lang. OutOfMemoryError: Requested array size exceeds limit VMCopy the code

Cause: The array created is larger than the heap memory

The Exception in the thread "main" : Java. Lang. OutOfMemoryError: request < size > bytes for < tiny >. Out of swap space?Copy the code

Cause: Local allocation failed. The JNI, local library, or Java virtual machine allocates memory space from the local heap.

The Exception in the thread "main" : Java. Lang. OutOfMemoryError: < "reason > < stack trace > (Native method)Copy the code

Cause: The same local method failed to allocate memory, only JNI or local method or Java virtual machine discovered