1. JVM memory area and object memory layout

1. Runtime data area

The memory area diagram of the JVM is as follows:

JVM memory area map

1.1, program counter

The Program Counter Register is a small memory space, which can be seen as a line number indicator of the bytecode executed by the current thread. In the conceptual model of the Java virtual machine [1], when the bytecode interpreter works, it selects the next bytecode instruction to be executed by changing the value of this counter. It is an indicator of program control flow, branching, and looping. Basic functions such as, jump, exception handling, and thread recovery all need to rely on this counter to complete. Since the multi-threading of the Java virtual machine is realized by the way of thread switching and allocating processor execution time in turn, at any certain moment, a processor (for a multi-core processor is a core) will only execute one Instructions in the thread. Therefore, in order to restore to the correct execution position after the thread is switched, each thread needs to have an independent program counter. The counters between the threads do not affect each other and are stored independently. We call this type 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 thread is executing a Native method, the counter value should be undefined. This memory area is the only area that does not specify any OutOfMemoryError conditions in the "Java Virtual Machine Specification".

1.2, virtual machine stack

Like the program counter, the Java Virtual Machine Stack (Java Virtual Machine Stack) is also thread-private, and its life cycle is the same as that of a thread. The virtual machine stack describes the thread memory model of Java method execution: when each method is executed, the Java virtual machine will synchronously create a stack frame to store local variable tables, operand stacks, dynamic connections, and methods. Export and other information. The process from when each method is called to the completion of execution corresponds to the process of a stack frame from pushing to popping in the virtual machine stack.

The storage space of these data types in the local variable table is represented by a local variable slot (Slot), where 64-bit long and double data will occupy two variable slots, and the remaining data types will only occupy one. The memory space required by the local variable table is allocated during compilation. When entering a method, how much local variable space this method needs to allocate in the stack frame is completely determined, and the size of the local variable table will not be changed during the running of the method. . Please note that the "size" mentioned here refers to the number of variable slots, how much memory space the virtual machine really uses (for example, according to a variable slot occupying 32 bits, 64 bits, or more) to realize a variable slot , This is completely determined by the implementation of the specific virtual machine. In the "Java Virtual Machine Specification", two types of abnormal conditions are specified for this memory area: If the stack depth requested by the thread is greater than the depth allowed by the virtual machine, a StackOverflowError exception will be thrown; if the Java virtual machine stack capacity can be dynamically expanded, When the stack is expanded, it will throw OutOfMemoryError if enough memory is not available.

1.3, local method stack

Native method stacks (Native Method Stacks) and virtual machine stacks play very similar roles. The difference is that the virtual machine stack serves the virtual machine to execute Java methods (that is, bytecode), while the native method stack serves the virtual machine. Native method service used by the machine. The "Java Virtual Machine Specification" does not have any mandatory provisions on the language, usage and data structure of the methods in the local method stack. Therefore, the specific virtual machine can freely implement it as needed, and even some Java virtual machines (such as Hot-Spot The virtual machine) directly combines the local method stack and the virtual machine stack into one. Like the virtual machine stack, the local method stack also throws StackOverflowError and OutOfMemoryError exceptions respectively when the stack depth overflows or the stack expansion fails.

1.4, Java heap

For Java applications, the Java Heap is the largest piece of memory managed by the virtual machine. The Java heap is a memory area shared by all threads and is created when the virtual machine starts. The sole purpose of this memory area is to store object instances, and "almost" all object instances in the Java world allocate memory here. The description of the Java heap in the "Java Virtual Machine Specification" is: "All object instances and arrays should be allocated on the heap", and the author here "almost" means that from an implementation point of view, with the Java language Now we can see some signs that support for value types may appear in the future. Even if we only consider now, due to the advancement of just-in-time compilation technology, especially the increasingly powerful escape analysis technology, the optimization methods of allocation on the stack and scalar replacement have led to Some subtle changes happen quietly, so that Java object instances are allocated on the heap and gradually become less absolute. The Java heap is a memory area managed by the garbage collector, so it is also called "GC heap" in some materials (Garbage Collected Heap, fortunately, it is not translated into "garbage heap" in China). From the perspective of reclaiming memory, since most modern garbage collectors are designed based on generational collection theory, there are often "new generation", "old generation", "permanent generation", "Eden space", and "From Survivor" in the Java heap. Nouns such as “space” and “To Survivor space” will appear repeatedly in subsequent chapters of this book. Here I want to explain first that these divisions are just some of the common features or design styles of garbage collectors. It is not the inherent memory layout implemented by a certain Java virtual machine, nor the further detailed division of the Java heap in the "Java Virtual Machine Specification". Many materials often say something like "The heap memory of the Java virtual machine is divided into young generation, old generation, permanent generation, Eden, Survivor...". Ten years ago (with the emergence of the G1 collector as the boundary), as the industry's absolute mainstream HotSpot virtual machine, its internal garbage collectors were all designed based on "classic generation", requiring the new generation and old generation collectors to match In this context, the above statement is not too ambiguous. But today, the garbage collector technology is not the same as it was ten years ago, and HotSpot has also published There is a new garbage collector that does not adopt generational design, and then there are many points to be discussed according to the above formulation. From the perspective of memory allocation, the Java heap shared by all threads can be divided into multiple thread-private allocation buffers (Thread Local Allocation Buffer, TLAB) to improve the efficiency of object allocation. However, no matter from any angle, no matter what the division, it will not change the commonality of the storage content in the Java heap. No matter which area, the storage can only be the instance of the object. The purpose of subdividing the Java heap is only for better recycling. Memory, or allocate memory faster. In this chapter, we only discuss the role of the memory area. The details of the allocation and recovery of the above-mentioned areas in the Java heap will be the subject of the next chapter. According to the "Java Virtual Machine Specification", the Java heap can be in a physically discontinuous memory space, but logically it should be regarded as contiguous. This is the same as when we use disk space to store files. Each document is required to be stored continuously. But for large objects (typically array objects), most virtual machine implementations are likely to require contiguous memory space for the sake of simple implementation and high storage efficiency. The Java heap can be implemented as a fixed size or expandable, but the current mainstream Java virtual machines are implemented in accordance with the scalability (set by the parameters -Xmx and -Xms). If there is no memory in the Java heap to complete the instance allocation, and the heap can no longer be expanded, the Java virtual machine will throw an OutOfMemoryError exception. According to the "Java Virtual Machine Specification", the Java heap can be in a physically discontinuous memory space, but logically it should be regarded as contiguous. This is the same as when we use disk space to store files. Each document is required to be stored continuously. But for large objects (typically array objects), most virtual machine implementations are likely to require contiguous memory space for the sake of simple implementation and high storage efficiency. The Java heap can be implemented as a fixed size or expandable, but the current mainstream Java virtual machines are implemented in accordance with the scalability (set by the parameters -Xmx and -Xms). If there is no memory in the Java heap to complete the instance allocation, and the heap can no longer be expanded, the Java virtual machine will throw an OutOfMemoryError exception. According to the "Java Virtual Machine Specification", the Java heap can be in a physically discontinuous memory space, but logically it should be regarded as contiguous. This is the same as when we use disk space to store files. Each document is required to be stored continuously. But for large objects (typically array objects), most virtual machine implementations are likely to require contiguous memory space for the sake of simple implementation and high storage efficiency. The Java heap can be implemented as a fixed size or expandable, but the current mainstream Java virtual machines are implemented in accordance with the scalability (set by the parameters -Xmx and -Xms). If there is no memory in the Java heap to complete the instance allocation, and the heap can no longer be expanded, the Java virtual machine will throw an OutOfMemoryError exception.

1.5, method area

The Method Area, like the Java heap, is a memory area shared by each thread. It is used to store data such as type information, constants, static variables, and code cache compiled by the just-in-time compiler that have been loaded by the virtual machine. Although the "Java Virtual Machine Specification" describes the method area as a logical part of the heap, it has an alias called "Non-Heap" to distinguish it from the Java heap. Speaking of the method area, I have to mention the concept of "permanent generation", especially before JDK 8, many Java programmers are used to developing and deploying programs on the HotSpot virtual machine, and many people prefer to call the method area " "Permanent Generation" (Permanent Generation), or confuse the two. In essence, the two are not equivalent, because the HotSpot virtual machine design team at the time chose to extend the generational design of the collector to the method area, or use permanent generation to implement the method area, which makes HotSpot garbage The collector can manage this part of the memory like the Java heap, saving the work of writing memory management code specifically for the method area. But for other virtual machine implementations, such as BEA JRockit, IBM J9, etc., there is no concept of permanent generation. In principle, how to implement the method area belongs to the implementation details of the virtual machine, which is not governed by the "Java Virtual Machine Specification" and does not require uniformity. But looking back now, the decision to use the permanent generation to implement the method area was not a good idea. This design made Java applications more likely to encounter memory overflow problems (permanent generation has the upper limit of -XX: MaxPermSize, even if it does not The setting also has a default size, and as long as J9 and JRockit do not touch the upper limit of the process available memory, such as the 4GB limit in a 32-bit system, there will be no problems), and there are very few methods (such as String:: intern()) will cause different performances under different virtual machines due to permanent generation. After Oracle acquired BEA and obtained the ownership of JRockit, it was ready to migrate the excellent features of JRockit, such as the Java Mission Control management tool, to the HotSpot virtual machine, but faced many difficulties due to the differences in the method area between the two. Taking into account the future development of HotSpot, in JDK 6, the HotSpot development team gave up the permanent generation and gradually changed to the plan of using native memory to implement the method area. In HotSpot of JDK 7, the original The permanent generation of string constant pools, static variables, etc. were moved out, and in JDK 8, the concept of permanent generation was finally completely abandoned. Instead, the metaspace (Metaspace) implemented in local memory like JRockit and J9 was used instead, and the JDK The remaining content (mainly type information) of the permanent generation in 7 is all moved to the meta space. The "Java Virtual Machine Specification" has very relaxed restrictions on the method area. In addition to the same as the Java heap, it does not require contiguous memory and can choose a fixed size or expandable. You can even choose not to implement garbage collection. Relatively speaking, garbage collection is indeed relatively rare in this area, but it is not that the data enters the method area as "permanent" as the name of the permanent generation. The goal of memory recovery in this area is mainly for the recovery of the constant pool and the unloading of types. Generally speaking, the recovery effect of this area is more difficult and satisfactory. Especially for the unloading of types, the conditions are quite harsh, but the recovery of this part of the area is sometimes It is indeed necessary. In the previous Sun company's bug list, several serious bugs that have appeared are due to the low version of the HotSpot virtual machine that did not fully reclaim this area, which led to memory leaks. The "Java Virtual Machine Specification" has very relaxed restrictions on the method area. In addition to the same as the Java heap, it does not require contiguous memory and can choose a fixed size or expandable. You can even choose not to implement garbage collection. Relatively speaking, garbage collection is indeed relatively rare in this area, but it is not that the data enters the method area as "permanent" as the name of the permanent generation. The goal of memory recovery in this area is mainly for the recovery of the constant pool and the unloading of types. Generally speaking, the recovery effect of this area is more difficult and satisfactory. Especially for the unloading of types, the conditions are quite harsh, but the recovery of this part of the area is sometimes It is indeed necessary. In the previous Sun company's bug list, several serious bugs that have appeared are due to the low version of the HotSpot virtual machine that did not fully reclaim this area, which led to memory leaks. The "Java Virtual Machine Specification" has very relaxed restrictions on the method area. In addition to the same as the Java heap, it does not require contiguous memory and can choose a fixed size or expandable. You can even choose not to implement garbage collection. Relatively speaking, garbage collection is indeed relatively rare in this area, but it is not that the data enters the method area as "permanent" as the name of the permanent generation. The goal of memory recovery in this area is mainly for the recovery of the constant pool and the unloading of types. Generally speaking, the recovery effect of this area is more difficult and satisfactory. Especially for the unloading of types, the conditions are quite harsh, but the recovery of this part of the area is sometimes It is indeed necessary. In the previous Sun company's bug list, several serious bugs that have appeared are due to the low version of the HotSpot virtual machine that did not fully reclaim this area, which led to memory leaks.

1.6, runtime constant pool

Runtime Constant Pool is part of the method area. In addition to the description information of the class version, fields, methods, and interfaces in the Class file, there is also a constant pool table (Constant Pool Table), which is used to store various literal and symbolic references generated during compile time. This part The content will be stored in the runtime constant pool in the method area after the class is loaded. The Java virtual machine has strict regulations on the format of each part of the Class file (naturally including the constant pool). For example, what kind of data each byte is used to store must meet the requirements of the specification before it can be recognized, loaded and executed by the virtual machine , But for the runtime constant pool, the "Java Virtual Machine Specification" does not make any detailed requirements. Virtual machines implemented by different providers can implement this memory area according to their own needs, but generally speaking, in addition to saving the Class file In addition to the symbolic references described, the direct references translated from the symbolic references are also stored in the runtime constant pool [1]. Another important feature of the runtime constant pool compared to the class file constant pool is that it is dynamic. The Java language does not require constants to be generated only at compile time, that is, the content of the constant pool that is not preset into the Class file can be entered. The method area is run-time constant pool, and new constants can also be put into the pool during runtime. This feature is used by developers more often in the intern() method of the String class. Since the runtime constant pool is part of the method area, it is naturally limited by the memory of the method area. When the constant pool can no longer apply for memory, it will throw an OutOfMemoryError exception.

1.7, direct memory

Direct Memory (Direct Memory) is not part of the data area of ​​the virtual machine runtime, nor is it the memory area defined in the "Java Virtual Machine Specification". But this part of the memory is also frequently used, and it may also cause OutOfMemoryError to appear, so we put it here to explain it together. In JDK 1.4, the NIO (New Input/Output) class was newly added, and a channel and buffer-based I/O method was introduced. It can use the Native function library to directly allocate off-heap memory, and then Operate by using a DirectByteBuffer object stored in the Java heap as a reference to this memory. This can significantly improve performance in some scenarios because it avoids copying data back and forth between the Java heap and the Native heap. Obviously, the allocation of native direct memory will not be limited by the size of the Java heap, but since it is memory, it will definitely be affected by the size of the total native memory (including physical memory, SWAP partition or paging file) and processor addressing space When configuring virtual machine parameters, general server administrators will set -Xmx and other parameter information according to the actual memory, but often ignore direct memory, making the sum of each memory area larger than the physical memory limit (including physical and operating system-level Limit), resulting in an OutOfMemoryError exception during dynamic expansion.

 

2. Exploring the HotSpot virtual machine object

2.1 Object creation

When the Java virtual machine encounters a bytecode new instruction, it will first check whether the parameter of this instruction can locate a symbol reference of a class in the constant pool, and check whether the class represented by the symbol reference has been loaded, resolved, and Initialized. If not, you must first perform the corresponding class loading process. After the class loading check passes, the virtual machine will then allocate memory for the new object. The size of the memory required by the object can be completely determined after the class is loaded.

Memory allocation methods include "pointer collision" and "free list" methods:

When Java memory is absolutely regular, it can be allocated using "pointer collision". All used memory is placed on one side, free memory is placed on the other side, and a pointer is placed in the middle as an indicator of the demarcation point. , The allocated memory just moves the pointer to the free space by a distance equal to the size of the object. This allocation method is called "Bump The Pointer". This allocation method can be used when using a mark-and-sort based GC algorithm.

When the memory in the Java heap is not regular, and the used memory and free memory are interlaced with each other, there is no way to simply collide pointers. The virtual machine must maintain a list of which memory blocks are recorded. If it is available, find a large enough space from the list to allocate to the object instance during allocation, and update the records on the list. This allocation method is called "Free List". This allocation method can be used when using a mark-and-sweep-based GC algorithm.

When dealing with concurrent allocation, there are two solutions: one is to synchronize the action of allocating memory space-in fact, the virtual machine uses CAS with failure retry to ensure the atomicity of the update operation; the other is to The action of memory allocation is carried out in different spaces according to the thread division, that is, each thread pre-allocates a small piece of memory in the Java heap, called the local thread allocation buffer (Thread Local Allocation Buffer, TLAB), which thread should allocate the memory , It is allocated in the local buffer of which thread, only when the local buffer is used up, the synchronization lock is required when a new buffer area is allocated. Whether the virtual machine uses TLAB can be set by the -XX:+/-UseTLAB parameter.

2.2 Object memory layout

The memory layout of objects in the HotSpot virtual machine can be divided into three: object header (Header), instance data (Instance Data) and alignment padding (Padding).

2.2.1, object header

       It is known from the picture that the object header is divided into two parts: Mark Word and Class Pointer.

Mark Word stores the object's hashCode, GC information, and lock information. Class Pointer stores a pointer to the information of the class object. On the 32-bit JVM, the size of the object header is 8 bytes, and the 64-bit JVM is 16 bytes. The two types of Mark Word and Class Pointer each occupy half of the space. There is a compressed pointer option -XX:+UseCompressedOops on the 64-bit JVM, which is enabled by default. After opening, the Class Pointer part will be compressed to 4 bytes, and the object header size will be reduced to 12 bytes.

The following is a picture showing the memory distribution of the object header on the 32-bit JVM, which is easy to understand.

2.2.2, instance data and alignment padding

       The variable memory allocation defined in the user program will be affected by the virtual machine allocation strategy parameter (-XX: FieldsAllocationStyle parameter) and the order in which the fields are defined in the Java source code. The default allocation order of HotSpot virtual machine is longs/doubles, ints, shorts/chars, bytes/booleans, oops (Ordinary Object Pointers, OOPs). As can be seen from the above default allocation strategy, fields with the same width are always allocated Stored together, in the case of meeting this prerequisite, the variables defined in the parent class will appear before the child class. If the +XX: CompactFields parameter value of the HotSpot virtual machine is true (the default is true), the narrower variables in the subclass can also be inserted into the gap of the parent class variable to save a little space. Since the automatic memory management system of the HotSpot virtual machine requires that the start address of the object must be an integer multiple of 8 bytes, in other words, the size of any object must be an integer multiple of 8 bytes, so if the object instance data part is not aligned Then you need to align.

2.3. Object access location

The mainstream access methods mainly include the use of handles and direct pointers:

1. If you use handle access, a piece of memory may be divided into the Java heap as a handle pool. The handle address of the object is stored in the reference, and the handle contains the specific address information of the object instance data and type data.

2. If you use direct pointer access, the memory layout of the object in the Java heap must consider how to place information about the access type data. The reference stored in the object is the address of the object directly. If you only access the object itself, you don’t need to do it again. The overhead of indirect access.

 

3. OutOfMemoryError exception

3.1, Java heap overflow

/**
* VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
* @author zzm
*/
public class HeapOOM {
    static class OOMObject {
    }
    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<OOMObject>();
        while (true) {
            list.add(new OOMObject());
        }
    }
}

The test code is as above, the OutOfMemoryError exception of Java heap memory is the most common memory overflow exception in practical applications. When a Java heap memory overflow occurs, the exception stack information "java.lang.OutOfMemoryError" will follow a further prompt "Java heap space".

To solve the anomaly in this memory area, the conventional processing method is to first analyze the heap dump snapshot from Dump through a memory image analysis tool (such as Eclipse Memory Analyzer). The first step is to confirm whether the objects in the memory that cause OOM are necessary, that is, to distinguish whether there is a memory leak (Memory Leak) or a memory overflow (Memory Overflow).

If it is a memory leak, you can further check the reference chain of the leaked object to the GC Roots through the tool, and find out what reference path the leaked object is through and which GC Roots are associated with, so that the garbage collector cannot reclaim them, according to the type of the leaked object Information and its information to the GC Roots reference chain can generally be more accurately located where these objects are created, and then find out the specific location of the code that caused the memory leak.

If it is not a memory leak, in other words all objects in the memory must be alive, then you should check the heap parameter (-Xmx and -Xms) settings of the Java virtual machine and compare it with the memory of the machine to see if there are any Upward adjustment space. Then check from the code whether there are some objects with too long life cycle, too long holding state time, unreasonable storage structure design, etc., to minimize the memory consumption during program operation.

3.2 Virtual machine stack and local method stack overflow

Regarding the virtual machine stack and the local method stack, two exceptions are described in the "Java Virtual Machine Specification":

1) If the stack depth requested by the thread is greater than the maximum depth allowed by the virtual machine, a StackOverflowError exception will be thrown.

2) If the stack memory of the virtual machine allows dynamic expansion, an OutOfMemoryError exception will be thrown when the expansion stack capacity cannot apply for enough memory.

/**
* 不停的递归导致栈溢出
* VM Args:-Xss128k
* @author zzm
*/
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;
        }
    }
}

/**
* 不停创建线程导致栈溢出
* VM Args:-Xss2M (这时候不妨设大些,请在32位系统下运行)
* @author zzm
*/
public class JavaVMStackOOM {
    private void dontStop() {
        while (true) {
        }
    }
    public void stackLeakByThread() {
        while (true) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    dontStop();
                }
            });
            thread.start();
        }
    }
    public static void main(String[] args) throws Throwable {
        JavaVMStackOOM oom = new JavaVMStackOOM();
        oom.stackLeakByThread();
    }
}

When a StackOverflowError exception occurs, there will be a clear error stack for analysis, which is relatively easy to locate the problem. If you use the default parameters of the HotSpot virtual machine, the stack depth is in most cases (because the frame size pushed into the stack by each method is not the same, so I can only say that in most cases) it is no problem to reach 1000~2000. For normal method calls (including recursive calls that cannot be optimized for tail recursion), this depth should be sufficient. However, if the memory overflow is caused by the establishment of too many threads, if the number of threads cannot be reduced or the 64-bit virtual machine cannot be replaced, the only way to exchange for more threads is to reduce the maximum heap and reduce the stack capacity. This method of "reducing memory" to solve memory overflow is generally difficult to think of without experience in this area. Readers need to pay attention to this point when developing multi-threaded applications for 32-bit systems. It is also because this problem is relatively hidden. Starting from JDK 7, after "unable to create native thread" in the above prompt message, the virtual machine specifically indicates that the reason may be "possibly out of memory or process/resource limits reached".

 

3.3 Method area and runtime constant pool overflow

/**
* 使用GLIBC不断生成动态类型导致方法区溢出
* VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
* @author zzm
*/
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 {
					return proxy.invokeSuper(obj, args);
				}
			});
			enhancer.create();
		}
	}
	static class OOMObject {
	}
}

Method area overflow is also a common memory overflow exception. If a class is to be recycled by the garbage collector, the conditions to be achieved are relatively harsh. In application scenarios where a large number of dynamic classes are generated during frequent operation, special attention should be paid to the recycling status of these classes. After JDK 8, the permanent generation has completely withdrawn from the stage of history, and Metaspace appears as its replacement.

HotSpot still provides some parameters as defense measures for metaspace, including:

-XX: MaxMetaspaceSize: Set the maximum metaspace size, the default is -1, that is, no limit, or only limited by the local memory size. ·

-XX: MetaspaceSize: Specify the initial space size of the metaspace, in bytes. When this value is reached, garbage collection will be triggered for type unloading, and the collector will adjust the value: if a large amount of space is released, it is appropriate Decrease this value; if very little space is released, increase the value appropriately if it does not exceed -XX: MaxMetaspaceSize (if set).

-XX: MinMetaspaceFreeRatio: The function is to control the percentage of the remaining capacity of the smallest metaspace after garbage collection, which can reduce the frequency of garbage collection due to insufficient metaspace. Similarly, there is -XX: Max-MetaspaceFreeRatio, which is used to control the percentage of the remaining capacity of the largest metaspace.

3.4 Native direct memory overflow

/**
* 通过Unsafe不断分配堆外内存最后导致本机内存溢出
* VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
* @author zzm
*/
public class DirectMemoryOOM {
	private static final int _1MB = 1024 * 1024;
	public 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.allocateMemory(_1MB);
		}
	}
}

The size of the direct memory (Direct Memory) can be specified by the -XX: MaxDirectMemorySize parameter. If it is not specified, the default is the same as the maximum Java heap (specified by -Xmx). An obvious feature of memory overflow caused by direct memory is that no obvious abnormalities will be seen in the Heap Dump file. If the reader finds that the Dump file generated after the memory overflow is very small, it is used directly or indirectly in the program. DirectMemory (typical indirect use is NIO), then you can consider focusing on checking the reasons for direct memory.

 

Reference: <In-depth understanding of the Java virtual machine: JVM advanced features and best practices third edition>

 

Guess you like

Origin blog.csdn.net/qq_32323239/article/details/108742375