当前位置:网站首页>Use of off heap memory
Use of off heap memory
2022-07-26 09:13:00 【Or turn around】
stay Jdk1.8 after ,jvm The memory model has been adjusted , That is, the implementation of the method area is from permanent generation (Perm Space) It becomes a meta space (MetaSpace). Metaspace is not in the virtual machine , Instead, it directly uses the system memory . For convenience , Hereinafter, virtual machine memory is called heap memory , Against it , Direct memory is called off heap memory .
Why use off heap memory
Before talking about why we should use off heap memory , We have to talk about heap memory . In heap memory is Java Virtual machine memory , Managed by virtual machines , Developers don't have to worry about the allocation and recycling of memory space . But there are advantages and disadvantages , The disadvantage of heap memory is :
- Garbage recycling has costs , The more objects in the heap ,GC The greater the cost .
- Use heap memory for file 、 Online IO when ,JVM Will use the off heap memory for an additional transfer , That is, one more memory copy .
And off heap memory directly uses machine memory , Managed by the operating system . To a certain extent, it reduces the impact of garbage collection on Applications .
Actual case
The blogger himself has never encountered the scene of having to use off heap memory in actual work . however 《 Ant message middleware (MsgBroker) stay YGC Exploration on Optimization 》 There is a relatively complete case in this article ( Reference material 2).
The business scenario in this article is the use of ant's message oriented middleware . To ensure the reliability of the message , Persisting messages to a database , In order to reduce the accuracy of message delivery db Reading pressure , The message is cached . In this way, the virtual machine will allocate memory for cached messages . When the message in the cache is not delivered successfully for various reasons , These news will be maintained all the time , And more and more . In heap space, objects change from young generation to old generation , It takes up more and more space . The final problem is that of the younger generation gc Time is too long ( exceed 100ms).
So here comes the question , Why does the increase of objects in old age lead to ygc The time is getting longer ? According to the answer in the text :
stay ygc Most of the time is older-gen scanning, This stage is mainly used to scan the references held by the elderly generation to the objects of the younger generation . In a scenario where messages are cached and a large number of messages cannot be delivered , A large number of young objects have been transformed into old objects , And holds references to younger generation objects . under these circumstances , The scanning time is relatively long .
The final solution is to use off heap memory , Reduce message pairs JVM Memory usage , And use the Netty Network layer framework , Achieved the ideal YGC Time .
Out of heap memory usage
Off heap memory can be used in two ways .
Unsafe Class action
sun.misc.Unsafe Provides a set of methods to allocate out of heap memory , Redistribute and release .
Unsafe yes java Back door for developers , It is used to directly operate the system memory and is not affected by jvm Have jurisdiction over , The implementation is similar to c++ Style operation . But generally, it is not recommended to use , As the class name shows , It's not safe , Easy to cause memory leaks .
Unsafe Most methods of class are native Method , Directly call methods in other languages ( For the most part c++) To operate , Many details cannot be traced , Can only roughly understand . Unsafe Class in jdk9 Then moved to jdk.unsupported Module .
- public native long allocateMemory(long size): Allocate memory space
- public native long reallocateMemory(long address, long size): Reallocate a piece of memory , The data from address Copy to the new memory block in the cache pointed to .
- public native void freeMemory(long address): Free memory
Unsafe The constructor of a class is private , Provides getUnsafe Method is used to get its instance . However, this method is not open to ordinary developers , Exceptions will be reported when using :java.lang.SecurityException: Unsafe
. You can use this class through the reflection mechanism . As shown below :
public class unsafeDemo {
public static void main(String[] args) {
Unsafe unsafe = null;
long memoryAddress = 0;
try {
// obtain Unsafe Private singleton object of type
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
memoryAddress = unsafe.allocateMemory(1024);
// take int Type integer is stored in the specified address
unsafe.putInt(memoryAddress, 5);
// Get an integer according to the address
int a = unsafe.getInt(memoryAddress);
System.out.println(a);
} catch (Exception e) {
e.printStackTrace();
} finally {
assert unsafe != null;
unsafe.freeMemory(memoryAddress);
}
}
}
NIO Class action
JDK1.4 Introduced NIO, have access to Native Function library directly allocates out of heap memory , And then through a Java In the pile DirectByteBuffer Object operates as a reference to this memory .
Allocate a block of off heap memory as follows :
ByteBuffer bf = ByteBuffer.allocateDirect(10 * 1024);
Check the source code to see allocateDirect Function definition of :
/**
* Allocates a new direct byte buffer.
*
* <p> The new buffer's position will be zero, its limit will be its
* capacity, its mark will be undefined, and each of its elements will be
* initialized to zero. Whether or not it has a
* {@link #hasArray backing array} is unspecified.
*
* @param capacity
* The new buffer's capacity, in bytes
*
* @return The new byte buffer
*
* @throws IllegalArgumentException
* If the <tt>capacity</tt> is a negative integer
*/
public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}
You can see , This method returns a DirectByteBuffer object . Further inspection DirectByteBuffer The creation process of :
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));
Bits.reserveMemory(size, cap);
long base = 0;
try {
base = unsafe.allocateMemory(size);
} 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 & (ps - 1));
} else {
address = base;
}
cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
att = null;
}
In the process , Real memory allocation is used Bits.reserveMemory Method .Bits.reserveMemory() The main logic is as follows :
- Bits Class has a global variable totalCapacity, Used to identify DirectByteBuffer The total size of . Every time I apply for memory , Check whether the size limit is exceeded first ( It can be done by -XX:MaxDirectMemorySize Set up ). If the limit has been exceeded , It will call System.gc(), Looking forward to actively reclaiming a little off heap memory . Then sleep for a while , have a look totalCapacity Is it available . If the memory is still insufficient , Throw out OOM abnormal .
Creating DirectByteBuffer The end of the object , adopt Cleaner.create(this, new Deallocator(base, size, cap)) Created a Cleaner object . The object's function is : When DirectByteBuffer When the object is recycled , Release its corresponding off heap memory .
Recovery of out of heap memory
Out of heap memory is based on GC The recycling of
As mentioned above , Out of heap memory passes through in heap DirectByteBuffer Object to reference .DirectByteBuffer The object itself is very small , But it represents a large amount of memory allocated , It's called “ Iceberg ” object . When DirectByteBuffer The object is gc when , The off heap memory it refers to will also be recycled .
in other words , The recycling of off heap memory is DirectByteBuffer Triggered when recycled , and DirectByteBuffer The recycling of is in the heap GC What happened .
Recall the pile GC The mechanism of : When the new generation is full , It will trigger YongGC, If the object is not invalidated at this time , Will not be recycled ; After several times YongGC After that, the objects of the new generation that still survive are moved to the elderly generation . When the old generation is full Full GC.
If DirectByteBuffer The object survived several times YongGC Later, they were migrated to the elderly generation , Even if it fails, it can stay in the elderly generation . be relative to YongGC, In the old days Full GC The frequency of is relatively low . It doesn't happen in the elderly Full GC when , Invalid DirectByteBuffer Objects always occupy a large amount of out of heap memory without releasing .
Of course , There is another situation that can also trigger DirectByteBuffer Recycling . That's what I mentioned above , When out of heap memory is applied and space is insufficient , Will call System.gc() To tell the virtual machine what to do GC 了 . But this way is not reliable , Because it will only be triggered when there is insufficient memory space outside the heap . and , If set -DisableExplicitGC It's forbidden system.gc(), Then it can't be recycled .
Active recycling of off heap memory
Active recycling of off heap memory refers to the use of DirectByteBuffer Of clean Object for memory recovery . As shown below :
public class ByteBufferTest {
public static void main(String[] args) throws Exception {
long size = Runtime.getRuntime().maxMemory();
System.out.println(" The default maximum out of heap memory is :" + size / 1024.0 / 1024.0 + "mb");
ByteBuffer bf = ByteBuffer.allocateDirect(1024 * 1024 * 1024);
Thread.sleep(2000);
System.out.println("cleaner start");
// clean(bf);
ByteBuffer bf2 = ByteBuffer.allocateDirect(1024 * 1024 * 1024);
Thread.sleep(2000);
clean(bf2);
}
private static void clean(final ByteBuffer byteBuffer) throws Exception {
if (byteBuffer.isDirect()) {
Field cleanerField = byteBuffer.getClass().getDeclaredField("cleaner");
cleanerField.setAccessible(true);
Cleaner cleaner = (Cleaner) cleanerField.get(byteBuffer);
cleaner.clean();
}
// // The second method is to get cleaner
// if (byteBuffer.isDirect()) {
// Cleaner cleaner = ((DirectBuffer)byteBuffer).cleaner();
// cleaner.clean();
// }
}
}
In no way -XX:MaxDirectMemorySize Parameter to specify the maximum out of heap memory , The default out of heap memory is similar to heap memory , adopt Runtime.getRuntime().maxMemory()
Can be obtained .
Then I applied 1024m Out of heap memory , And pass cleaner I did an out of heap memory recycling . Then apply again 1024m Out of heap memory . The operation effect is as follows :
The default maximum out of heap memory is :1753.0mb
cleaner start
If you comment out clean(bf) This business , There's no problem running . As mentioned above , When there is insufficient space to apply for out of heap memory , The system will call System.gc() To trigger Full GC, In order to achieve the purpose of reclaiming memory outside the heap .
If you comment out clean(bf) meanwhile , Appoint -XX:+DisableExplicitGC Parameter to prohibit explicit triggering gc, When applying for the second off heap memory , Will report OOM error , because System.gc() The call to is invalid . The running results are as follows :
Reference material
[1]. https://www.jianshu.com/p/17e72bb01bf1
[2]. https://juejin.im/post/5a9cb49df265da239706561a?utm_source=gold_browser_extension
[3]. https://www.jianshu.com/p/ae3847326e69
边栏推荐
猜你喜欢
Day06 homework - skill question 7
Grain College of all learning source code
论文笔记: 知识图谱 KGAT (未完暂存)
分布式跟踪系统选型与实践
垂直搜索
Flask project learning (I) -- sayhello
ext3文件系统的一个目录下,无法创建子文件夹,但可以创建文件
Study notes of automatic control principle -- correction and synthesis of automatic control system
李沐d2l(五)---多层感知机
NPM add source and switch source
随机推荐
[use of final keyword]
SQL入门——组合表
网络安全漫山遍野的高大上名词之后的攻防策略本质
Server memory failure prediction can actually do this!
Advanced mathematics | Takeshi's "classic series" daily question train of thought and summary of error prone points
ONTAP 9文件系统的限制
Web overview and b/s architecture
Flask project learning (I) -- sayhello
756. Serpentine matrix
Pop up window in Win 11 opens with a new tab ---firefox
Pytoch realizes logistic regression
The idea shortcut key ALT realizes the whole column operation
Grain College of all learning source code
力扣链表题
【无标题】
Numpy Foundation
(1) CTS tradefed test framework environment construction
209. Subarray with the smallest length
2022化工自动化控制仪表操作证考试题模拟考试平台操作
Voice chat app source code - Nath live broadcast system source code