一个应用程序如何读取数据,用户态不能直接操作操作系统,由用户态切换为内核态,然后执行io操作,这个时候将磁盘文件数据读取到系统内存的系统缓存区,但是java并不能直接读取系统缓存区的数据,这个时候要将系统缓存区复制一份数据到java缓冲区,这样效率就不高,因此,引入了直接内存,这个直接内存就是相当于在系统缓存区和java缓存区搭了一个桥梁,是互通的,在这种情况下,磁盘文件直接上传到直接内存当中,然后内核态读取。讲一下底层原理,由DMA从网卡缓冲区将数据拷贝到系统的内核缓冲区,由内核将内核缓冲区的数据拷贝到用户态的用户缓冲区,数据拷贝阶段完成了。
这样java程序就可以直接读取数据,不需要复制一遍。
但是直接内存不受JVM内存回收管理,需要unsafe进行内存的回收和释放
ByteBuffer的实现类内部,使用了Cleaner(虚引用)来监测ByteBuffer对象,一旦ByteBuffer对象被垃圾回收,那么就会由ReferenceHandler线程通过Cleaner的clean方法调用freeMemory来释放直接内存。但是如果显示地进行垃圾回收System.gc(),这是full gc这样会很影响性能,因此我们可以使用unsafe.freeMemory来释放内存。