这是我参与更文挑战的第19天,活动详情查看: 更文挑战 堆外内存 堆外内存,其实就是不受JVM控制的内存。简单来说,除了堆栈内存,剩下的就都是堆外内存了(当然,这是从Java运行时内存的角度来看),堆外内存直接受操作系统管理,而不是虚拟机。而使用堆外内存的原因, 相比于堆内内存有几个优势: 减少了垃圾回收的工作,因为垃圾回收会暂停其他的工作(可能使用多线程或者时间片的方式,根本感觉不到) 堆外内存是直接受操作系统管理的,而不是JVM,因此使用堆外内存的话,就可以保持一个比较小的堆内内存,减少垃圾回收对程序性能的影响。 就是提高IO操作的效率!这里就涉及用户态与内核态,以及内核缓冲区的概念,如果从堆内向磁盘写数据,数据会被先复制到堆外内存,即内核缓冲区,然后再由OS写入磁盘,但使用堆外内存的话则可以避免这个复制操作。 堆内内存其实就是用户进程的【进程缓冲区】,属于用户态;堆外内存由操作系统管理【内核缓冲区】,属于内核态。 自然也有不好的一面: 堆外内存难以控制,如果内存泄漏,那么很难排查 堆外内存相对来说,不适合存储很复杂的对象。一般简单的对象或者扁平化的比较适合。 因为是操作系统的内存机制,所以需要通过本地方法进行分配,较为复杂和缓慢 直接内存使用 堆外内存通过java.nio的ByteBuffer来创建,调用allocateDirect方法申请即可。 可以通过设置-XX:MaxDirectMemorySize=10M控制堆外内存的大小。 堆外内存的垃圾回收 由于堆外内存并不直接控制于JVM,因此只能等到full GC的时候才能垃圾回收!Full GC,一般发生在年老代垃圾回收以及调用System.gc的时候,这样肯定不能满足我们的需求! 手动的控制回收堆外内存了!其中sun.nio其实是java.nio的内部实现。 package xing.test; import java.nio.ByteBuffer; import sun.nio.ch.DirectBuffer; public class NonHeapTest { public static void clean(final ByteBuffer byteBuffer) { if (byteBuffer.isDirect()) { ((DirectBuffer)byteBuffer).cleaner().clean(); } } public static void sleep(long i) { try { Thread.sleep(i); }catch(Exception e) { /*skip*/ } } public static void main(String []args) throws Exception { ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024 * 200); System.out.println("start"); sleep(5000); c