https://www.jianshu.com/p/007052ee3773
Heap out of Memory release code: http://blog.csdn.net/z69183787/article/details/79316599 heap External memory
The outer heap memory is a concept relative to the memory in the heap. In-heap memory is the Java process memory controlled by the JVM, and the objects we normally create in Java are in memory in the heap, and they follow the memory management mechanism of the JVM, where the JVM uses the garbage collection mechanism to manage their memory uniformly. Then the heap of memory is an area of memory that exists outside the JVM's control, so it is not regulated by the JVM.
before explaining Directbytebuffer, you need to understand two knowledge points first Java reference type, because Directbytebuffer is the release of heap memory through a virtual reference (Phantom Reference).
Phantomreference is the weakest reference type in all "weak references". Unlike soft references and weak references, a virtual reference cannot use the Get () method to obtain a strong reference to the target object, thereby using the target object, and observing the source can find that get () is rewritten to return null forever.
What is the effect of the virtual reference. In fact, a virtual reference is primarily used to track the state of an object being garbage collected, and to take action by looking at whether the reference queue contains a virtual reference to the object that it is about to be garbage collected. It is not expected to be used to obtain a reference to the target object, and before the target object is reclaimed, its reference is placed in a Referencequeue object, thereby tracking the object garbage collection.
About the implementation and principles of Java reference types you can read the previous article reference, Referencequeue and Java reference type brief on Linux kernel State and user state
Kernel state: Controls the hardware resources of the computer and provides an environment in which the upper application runs. such as socket i/0 operation or file read and write operation, such as user state: The upper application of the active space, application execution must rely on the resources provided by the kernel. System calls: To enable upper-level applications to access these resources, the kernel provides access to upper-level applications.
So we can learn that the native method that we call through JNI is actually a way of switching from user state to kernel state. and using the system to invoke the functionality provided by the operating system.
Q: Why do I need a user process (in user state) to invoke resources in the kernel state through system calls (even JNI in Java), or invoke the service of the operating system.
The A:intel CPU provides ring0-ring3 four levels of operating mode, with the highest RING0 level and the lowest Ring3. Linux uses the RING3 level to run the user state, RING0 as the kernel state. The RING3 state does not have access to the RING0 address space, including code and data. Therefore the user State is not authorized to operate the kernel state of the resources, it can only through the system call to complete the user state to the kernel state of the switch, and then after the completion of the relevant operation of the kernel state switch back to user state.
directbytebuffer ———— Direct buffering
Directbytebuffer is an important class of Java used to implement heap memory, through which we can create, use, and destroy the outer heap of memory.
Directbytebuffer The class itself is still in a heap in the Java memory model. In-heap memory is the JVM that can be directly controlled and manipulated.
The unsafe.allocatememory (size) in the Directbytebuffer is a native method that allocates the outer heap of memory and allocates it through the malloc of C. The allocated memory is a system-local memory, not in Java memory, nor in the JVM's control range, so there must be some way to manipulate the directbytebuffer memory.
There is an address attribute in the Directbytebuffer's parent class buffer:
Used only by direct buffers
//note:hoisted this for speed into JNI getdirectbufferaddress
long address;
Address is only cached directly to use. The Address property upgrade was placed in buffer to elevate the rate at which it was invoked when Jni called Getdirectbufferaddress.
Address represents the location of the allocated heap of external memory.
Unsafe.allocatememory (size); After the heap of memory is allocated, the allocated heap of memory base address is returned and assigned to the Address property. This allows us to use this address to implement this heap of memory operations later through JNI.
As we said before, the kernel-state permissions are the highest in Linux, so in a kernel-state scenario, the operating system can access any memory area, so the operating system can access the memory area of the Java heap.
Q: Why does the operating system not directly access the memory area within the Java heap?
A: This is because the Jni method accesses an area of memory that has been identified as a region of memory, so that the memory address is directed to the memory in the Java heap, so if the operating system is accessing this memory address, Java at this time has a GC operation, The GC operation will involve the movement of data [GC will often do the first sign in the compression operation. That is, to mark the recyclable space, then empty the memory of the flag location, then a compression, the compression will involve the movement of objects, the purpose of the move is to make a more complete, contiguous memory space to accommodate a larger new object, and the movement of data will cause JNI call data confusion. Therefore, the memory of the JNI call is not available for GC operation.
Q: As mentioned above, the JNI call memory is not a GC operation, then how to solve it.
A:① the way in which data is copied between the memory in the heap and the memory in the heap (and the JVM guarantees that no GC will be performed when the memory of the heap is copied to the outer heap): For example, we want to complete an operation that reads data from a file into the memory in the heap, i.e. Filechannelimpl.read Heapbytebuffer). Here, actually, the file I/O reads the data into the heap memory, and then the heap memory copies the data to the heap, so that we can read the memory in the file.
static int Read (FileDescriptor var0, Bytebuffer var1, Long var2, Nativedispatcher var4) throws IOException {if (v
Ar1.isreadonly ()) {throw new IllegalArgumentException ("Read-only buffer");
else if (var1 instanceof Directbuffer) {return Readintonativebuffer (var0, var1, Var2, VAR4);
else {//Allocate temporary heap memory bytebuffer VAR5 = Util.gettemporarydirectbuffer (var1.remaining ());
int var7;
The try {//File I/O operation reads data into the heap in memory int var6 = Readintonativebuffer (var0, VAR5, Var2, VAR4);
Var5.flip ();
if (Var6 > 0) {//Copy the data of the heap outside memory into the outer heap memory Var1.put (VAR5);
} VAR7 = VAR6; Finally {//inside will call Directbuffer.cleaner (). Clean () to free temporary heap memory Util.offerfirsttemporarydirec
Tbuffer (VAR5);
return VAR7;
}
}
Instead, we write the data lines of the memory in the heap to the outside of the heap, and the operating system writes the data from the heap memory to the file.
② directly uses heap memory, such as Directbytebuffer: This way is to allocate a memory directly outside the heap (that is, native memory) to store the data, and the program reads/writes the data directly into the heap memory through JNI. Because the data is written directly into the heap of memory, it is no longer possible to allocate memory in the JVM-controlled heap to store the data, and there is no operation in the heap of memory and the data copies of the outer heap. So when I am doing an I/O operation, I just need to pass this heap of memory address to the JNI I/O function.
Directbytebuffer The source code of the creation and recovery of the outer heap memory heap outside memory allocation
Directbytebuffer (int cap) {//Package-private super ( -1, 0, cap, CAP);
Boolean PA = vm.isdirectmemorypagealigned ();
int ps = Bits.pagesize ();
Long size = Math.max (1L, (long) cap + (PA ps:0));
reserves the size of total allocated memory (allocated by page) and the size of the actual memory bits.reservememory (size, cap);
Long base = 0;
The try {///unsafe.allocatememory allocates the heap outer memory and returns the base address base = unsafe.allocatememory (size) of the outer heap memory;
catch (OutOfMemoryError x) {bits.unreservememory (size, cap);
throw x;
Unsafe.setmemory (base, size, (byte) 0); if (PA && (base% PS!= 0)) {//Round up to page boundary address = base + PS-(base &am P
(ps-1));
else {address = base; The//Build cleaner object is used to track garbage collection of Directbytebuffer objects so that when Directbytebuffer is garbage collected, the heap outer memory is also released cleaner = Cleaner.create (
This, new Deallocator (base, size, cap)); ATT =Null
}
bits.reservememory (size, cap) method
static void Reservememory (long size, int cap) {if (!memorylimitset && vm.isbooted ()) {Maxme
Mory = Vm.maxdirectmemory ();
Memorylimitset = true;
}//optimist!
if (tryreservememory (size, cap)) {return;
Final javalangrefaccess JLRA = sharedsecrets.getjavalangrefaccess (); Retry while helping Enqueue pending Reference objects//which includes executing pending Cleaner (s) which incl Udes//Cleaner (s), free direct buffer memory while (Jlra.tryhandlependingreference ()) {I
F (tryreservememory (size, cap)) {return;
}//Trigger VM ' s Reference processing System.GC (); A retry loop with exponential back-off delays//(this gives VM some time to do it ' s job) boolean Inter
rupted = false;
try {long sleeptime = 1;
int sleeps = 0; while (true) {if (Tryreservememory (size, cap)) {return;
} if (sleeps >= max_sleeps) {break; } if (!jlra.tryhandlependingreference ()) {try {thread.sleep (
Sleeptime);
Sleeptime <<= 1;
sleeps++;
catch (Interruptedexception e) {interrupted = true;
}}//No luck throw new OutOfMemoryError ("Direct buffer Memory"); Finally {if (interrupted) {//don ' t swallow interrupts thread.cur
Rentthread (). interrupt (); }
}
}
This method is used to save the total allocated memory (allocated by page) and the actual memory size in the system.
Where the memory in the system (that is, the heap of memory) is not enough:
Final javalangrefaccess JLRA = sharedsecrets.getjavalangrefaccess ();
Retry while helping Enqueue pending Reference objects
//which includes executing pending Cleaner (s) which includes
//Cleaner (s), free direct-buffer memory while
(Jlra.tryhandlependingreference ()) {
if ( Tryreservememory (size, cap)) {return
;
}
}
Jlra.tryhandlependingreference () triggers a non blocking reference#tryhandlepending (false). This method frees the heap memory of the Directbuffer object that has been garbage collected by the JVM.
Because it is defined in the static code block of reference:
Sharedsecrets.setjavalangrefaccess (New Javalangrefaccess () {
@Override public
Boolean Tryhandlependingreference () {return
tryhandlepending (false);
}
});
If there is not enough memory allocation for this heap after an external heap memory resource collection, the
Trigger VM ' s Reference processing
System.GC ();
System.GC () triggers a full GC, assuming that you do not display the settings-XX:+DISABLEEXPLICITGC to disable the explicit GC. And you need to know that calling System.GC () does not guarantee that the full GC will be executed immediately.
So in the back code, a maximum of 9 attempts will be made to see if there is enough free heap memory to allocate the heap of the outer memory. And before each attempt, deferred latency was given, giving the JVM enough time to complete the full GC operation. Throws a OutOfMemoryError ("Direct buffer Memory") exception if there is still not enough available heap memory to allocate this heap outside memory after 9 attempts.
Note that one of the most important reasons for using the full GC is that System.GC () will reclaim memory for the generation of new generations, which can be more thoroughly recycled directbytebuffer objects and their associated heap memory. The
Directbytebuffer object itself is actually small, but it may be associated with a very large heap of memory, so we often call it the Iceberg object.
When we do the YGC, we will reclaim the unreachable Directbytebuffer objects and their heap memory in the Cenozoic, but we cannot recycle the Directbytebuffer objects in the old and their heap memory, which is the biggest problem we usually encounter. (and extra heap memory is used for objects of medium or longer lifetime)
If a large number of Directbytebuffer objects are moved to the old, but have not done a CMS GC or full GC, and only YGC, then our physical memory may be depleted, but we don't know what happened, Because heap obviously the remaining memory is still a lot (if we disable the SYSTEM.GC–JVM parameter DISABLEEXPLICITGC).
In general, the bits.reservememory (size, cap) method implements the following steps to try to complete the creation of this external heap of memory when the available heap memory is not sufficient to allocate to the amount of heap memory currently being created:
① triggers a non blocking reference#tryhandlepending (false). This method frees the heap memory of the Directbuffer object that has been garbage collected by the JVM.
② If there is not enough memory allocation for this heap after an external heap memory resource collection, then System.GC (). System.GC () triggers a full GC, but you need to be aware that calling System.GC () does not guarantee that the full GC will be executed immediately. So in the back code, a maximum of 9 attempts will be made to see if there is enough free heap memory to allocate the heap of the outer memory. And before each attempt, deferred latency was given, giving the JVM enough time to complete the full GC operation.
Note that if you set the-XX:+DISABLEEXPLICITGC, the display GC will be disabled, which will invalidate the System.GC () call.
③ throws a OutOfMemoryError ("Direct buffer Memory") exception if there is still not enough available heap memory to allocate this heap of external memory after 9 attempts.
So what is the amount of available heap memory. , that is, how large the default heap memory is:
① If we do not specify the maximum heap memory through-xx:maxdirectmemorysize. The?
② If we don't specify this property by-dsun.nio.maxdirectmemorysize, and it's not equal to 1. The?
③ the value of the maximum heap outer memory is derived from the Directmemory = Runtime.getruntime (). MaxMemory (), which is a native method
Jniexport jlong jnicall
java_java_lang_runtime_maxmemory (jnienv *env, jobject this)
{return
jvm_ MaxMemory ();
}
Jvm_entry_no_env (Jlong, jvm_maxmemory (void))
jvmwrapper ("Jvm_maxmemory");
size_t n = universe::heap ()->max_capacity ();
return Convert_size_t_to_jlong (n);
Jvm_end
In the case where we use the CMS GC, which is the value of the-xmx we set, the size of the default heap is the size of the survivor.
Heap External Memory recovery
Cleaner is a phantomreference subclass of a two-way list maintained by its own next and Prev fields. The role of Phantomreference is to track the garbage collection process and does not cause any impact to the garbage collection process of the object.
So Cleaner = Cleaner.create (This, new Deallocator (base, size, cap)); Used to track the garbage collection process of the currently constructed Directbytebuffer object.
When the Directbytebuffer object--> enqueue state from the pending state, the clean () of cleaner is triggered, and the Cleaner Clean () method implements the release of the heap memory through unsafe.
? Although cleaner does not call to Reference.clear (), The Cleaner Clean () method calls remove (this) to remove the current cleaner from the cleaner list, so that when clean () is finished, Cleaner is an object that has no reference to it, that is, an object that can be reclaimed by GC.
Thunk Method:
to reclaim the outer heap of memory by configuring parameters
At the same time we can specify the maximum size of the heap memory by-xx:maxdirectmemorysize, and when the threshold is reached, the System.GC () is called to do a full GC to reclaim the unused heap of memory.
Heap of memory those things the reason for using the outer heap memoryImprovements to the waste recycling pause
Because the full GC means a thorough recycle, the garbage collector scans all allocated heap memory in a complete way, which means an important fact-the effect of such a garbage collection on Java applications is proportional to the size of the heap. Too large a heap can affect the performance of Java applications. If you use external memory, the heap of external memory is directly managed by the operating system (not the virtual machine). The result is to keep a smaller amount of memory in the heap to reduce the impact of garbage collection on applications. The performance of program I/O manipulation can be elevated in some scenarios. The steps to copy data from the heap's memory to the outer heap memory are less.
Under what circumstances is the heap of external memory usedThe outer heap memory applies to objects that are medium or long in life cycles. (if it is a shorter lifecycle object, it is recycled at ygc time, there is no large memory and long life cycle of objects in the FGC to the application caused by the performance impact). Direct file copy operations, or I/O operations. The direct use of heap memory allows less memory to be copied from user memory to system memory, because I/O operations are communication between the system kernel memory and the device, rather than through programs that communicate directly with peripherals. At the same time, you can use the pool + heap of memory combination way to the short life cycle, but involves I/O operation of the object for the reuse of heap memory. (This method is used in Netty)
Heap External Memory VS memory poolMemory pool: Mainly used in two types of objects: ① short life cycle, and simple structure of objects, in the memory pool reuse these objects can increase the CPU cache hit ratio, thereby improving performance; ② loads large amounts of data that contains a large number of duplicate objects, and using a memory pool can reduce the time spent in garbage collection. Heap external memory: It can shorten garbage collection time as well as the memory pool, but it is the exact opposite of the object and memory pool. Memory pools tend to be used for shorter life-span objects, while those with a medium or long life span are the object of heap memory to resolve.
the characteristics of the outer heap memoryGood scalability for large memory the improvement of garbage collection pauses can be perceived to be shared between processes, reducing replication between virtual machines
Some problems with the outer heap memoryThe problem of heap memory recovery and the leakage of external memory. This source analysis above has already mentioned the data structure problem of the external memory: the biggest problem with the heap memory is that your data structure becomes less intuitive, if the data structure is more complex, it should be serialized (serialization), and the serialization itself will affect the performance. Another problem is that because you can use larger memory, you may start to worry about the speed of virtual memory (i.e., hard drive) affecting you.
Reference
http://lovestblog.cn/blog/2015/05/12/direct-buffer/
Http://www.infoq.com/cn/news/2014/12/external-memory-heap-memory
Http://www.jianshu.com/p/85e931636f27