Java knowledge learning - direct memory

For direct memory, when we talked about the JVM memory structure, there is no area called direct memory, but the method area, heap, and stack. Direct memory does not belong to the memory management of the JVM, but to the memory management of the system, that is, the direct memory is the memory of the operating system. For direct memory the definition is as follows:

  • Commonly used in NIO operations for data buffers
  • The cost of allocation recovery is high, but the read and write performance is high
  • Not subject to JVM memory recovery management

There is a commonly used class in NIO—ByteBuffer, which is the direct memory used directly. Copying large files through ByteBuffer is much faster than ordinary blocking IO.

Java itself does not have the ability to read and write disks. To achieve disk reading and writing, functions provided by the operating system must be called, that is, switching from Java methods to local methods. The CPU will also switch from the user state (Java) to the kernel state (System), and then there are some related operations in the memory. When switching to the kernel state, the CPU function can actually read and write the contents of the disk file. Read from the disk file, because the system memory is used in the kernel mode, so after the reading is completed, a buffer will be drawn in the system memory to store the read file, and the buffer will be used to read in batches , but the system buffer cannot run for Java code, so Java will divide a Java buffer in the Java heap memory. To access the data in the stream just read by the Java code, it must be indirectly read from the system buffer into the Java buffer. When the Java buffer reaches the next state of Java, it will call other write operations, etc. The target file is copied to the target location after repeated reading and writing. It is easy to find that there is a problem, two memory and two buffers, the system memory has a buffer, and the Java memory has a buffer. When reading, the data must be stored in two copies. The first time the system buffer is read , and then read from the system buffer to the Java buffer, so that it becomes an unnecessary data copy, so the efficiency is not very high.

The effect after using direct memory is very different. When we call the allocateDirect method of ByteBuffer, it will directly allocate a piece of direct memory. After this method is called, a buffer will be drawn on the operating system side, which is the Direct memory in the figure below. The drawn buffer is the largest The feature is that Java code can be directly accessed, in other words, this block of memory, both Java and the system can use it, it is a memory area shared by both blocks. When reading and writing a disk file, it will directly read and write it into the Dict memory, and the Java code can directly read the data from the buffer, which is one less copy operation of the buffer data than the above method, so the speed is improved. times the improvement.

 

Direct memory will not be managed by JVM's memory recovery, so direct memory will have the problem of memory overflow. Garbage collection releases useless objects automatically in Java and does not require us to manually call any methods, but direct memory is different. It must be our initiative to call the freeMemory method in the Unsafe class to complete the release of memory. The Unsafe class is associated with ByteBuffer. When the allocateDirect method of ByteBuffer is called, the actual implementation is to complete the allocation of direct memory through the two methods of allocateMemory and setMemory of Unsafe. So when will Unsafe's freeMemory method be called? Because we say that the release of direct memory is achieved through the freeMemory method of Unsafe, the key here is the Cleaner.

The bottom layer of ByteBuffer's allocateDirect method​​​​

 

Regarding Cleaner, first look at the callback task object Deallocator (which implements the Runable interface). The run method in this callback task object calls Unsafe's freeMemory method, which also verifies that the direct memory must be released by the Unsafe object.

Callback task object Deallocator

For Cleaner, it belongs to a special type in the Java class library - virtual reference type. Its characteristic is that when its associated object is recycled, it will trigger a Clean method of virtual reference. In the bottom layer of the allocateDirect method of ByteBuffer, we can see that the Cleaner is actually associated with DirectByteBuffer, and DirectByteBuffer is a Java object, so when the DirectByteBuffer object is garbage collected, it will execute the run method of our task object.

The Clean method of the Cleaner object

 

 However, there is a problem with the release of direct memory. When tuning the JVM, the display recycling is generally disabled (that is, System.gc() is invalid), because the display recycling is actually a Full GC, whether it is the new generation or the old generation. All releases will cause the program to pause for a long time, so in order to prevent this situation, the parameter -XX:+DisableExplicitGC will be added to JVM tuning to disable display recycling. Adding this will affect the release mechanism of direct memory, because objects like ByteBuffer will not be recycled when there is sufficient memory, so they will always occupy direct memory. In order to solve this problem, you can manually release the direct memory, that is, directly call the freeMemory method of Unsafe, and manually call the allocation and release of the direct memory.

 

Guess you like

Origin blog.csdn.net/qq_35363507/article/details/104546910