并不属于JVM管理,属于系统内存,即操作系统的内存
- 常见于NIO操作,用于数据缓冲区
- 分配回收成本高,但读写性能高
- 不受JVM内存回收管理
传统的阻塞IO
使用直接内存
观看耗时:
说明直接内存远远快于传统的方式
原理 -- 为什么读写效率变高
java本身并不具备磁盘读写的能力,他要使用操作系统的方法,其实就是调用native方法 ,会涉及到用户态和内核态的切换,当切换到内核态,就可以由cpu的函数读取磁盘文件的内容,在操作系统内存划分出一块系统缓冲区,磁盘的内容存储到系统缓冲区,但是系统缓冲区Java代码是不能进行操作的,所以java也会在堆内存中分配一个java缓冲区,就是我们new的Byte数组,java要访问到系统缓冲区的数据,就要将系统缓冲区的内容读入到java缓冲区,因为现在有两块缓冲区,数据必然要存两份,造成不必要的浪费,效率不高
当调用ByteBuffer.allocateDirect()方法时,意味着会在操作系统中划分一块缓冲区,但是这块缓冲区不同的是,java系统可以访问到这块内存,那加入直接内存后,磁盘文件读取的时候,直接读取到直接内存,而java代码也可以读取到,少了一次数据的拷贝操作。
内存溢出
既然直接内存不受jvm管理,会不会导致内存溢出呢
执行代码,我们发现会有内存的溢出
释放原理
我们执行程序,发现该程序占用了1G的内存
我们发现置位null之后,内存占用变少,说明回收掉了
分配和回收原理
- 使用了Unsafe对象完成直接内存的分配回收,并且回收需要主动freeMemory方法
- ByteBuffer的实现类内部,使用了Cleaner(虚引用)来监测ByteBuffer对象,一旦ByteBuffer对象被垃圾回收,那么就会由ReferenceHandler线程通过Cleaner的clean方法调用freeMemory来释放直接内存。
禁用System.gc() ==> 显示的进行垃圾回收
触发的是FullGC,即也会回收老年代的垃圾