堆外内存

一、什么是堆外内存

堆外内存是相对于堆内内存的一个概念。堆内内存是由JVM所管控的Java进程内存,我们平时在Java中创建的对象都处于堆内内存中,并且它们遵循JVM的内存管理机制,JVM会采用垃圾回收机制统一管理它们的内存。那么堆外内存就是存在于JVM管控之外的一块内存区域,因此它是不受JVM的管控

可以通过设置-XX:MaxDirectMemorySize=10M控制堆外内存的大小

二、使用堆外内存的优缺点

1.堆外内存的优点

减少了垃圾回收的工作,因为垃圾回收会暂停其他的工作(可能使用多线程或者时间片的方式,根本感觉不到)
加快了复制的速度。因为堆内在flush到远程时,会先复制到直接内存(非堆内存),然后在发送;而堆外内存相当于省略掉了这个工作。

2.堆外内存的缺点

堆外内存难以控制,如果内存泄漏,那么很难排查
堆外内存相对来说,不适合存储很复杂的对象。一般简单的对象或者扁平化的比较适合。

三、DirectByteBuffer

操作系统中除了jvm申请的内存外,还有一块jvm以外的内存,这块内存空间一船是连续的,DirectByteBuffer对象是在jvm申请和创建的,内容是在堆外内存存放的的,DirectByteBuffer保存申请堆外内存时的起始偏移地址和堆外内存申请的容量。


Bits:记录申请堆外内存的大小及创建Unsafe对象
Unsafe:申请堆外内存和销毁堆外内存
Deallocator:堆外内存回收线程
Cleaner: Cleaner.create()需要2个参数:第一个参数:需要监控的堆内存对象DirectByteBuffer,第二个参数:程序释放资源的回调Deallocator。当JVM进行GC的时候,如果发现我们监控的对象,不存在强引用了(只被Cleaner对象引用,这是个幽灵引用),就会调用第二个参数Deallocator.run()方法的逻辑,执行完Deallocator.run()的时候(这个时候已经释放了堆外内存),JVM会自动释放堆内存中我们监控的对象。

申请堆外内存步骤:
1. 调用unsafe.allocateMemory申请堆外内存并获得起始地址偏移量
2. 调用unsafe.setMemory始初化堆外内存数据为0
3. 调用Bits.reserveMemory保存申请的堆外内存的数量
4. 初始化Cleaner对象,传入回调线程Deallocator

回收逻辑是在Deallocator.run方法里:
1. 调用unsafe.freeMemory释放内存
2. 调用Bits.unreserveMemory减少堆外内存的数量


四、堆外内存泄漏

点击打开链接


没有更多推荐了,返回首页