Java知识学习——直接内存

对于直接内存,前面在说JVM内存结构的时候,并没有一个区域叫做直接内存,都是方法区、堆和栈。直接内存并不是属于JVM的内存管理,而是属于系统的内存管理,即直接内存是操作系统的内存。对于直接内存定义如下:

  • 常见于NIO操作时,用于数据缓冲区
  • 分配回收成本较高,但读写性能高
  • 不受JVM内存回收管理

在NIO有一个经常用的类——ByteBuffer,就是直接使用的直接内存,通过ByteBuffer拷贝大文件就比普通的阻塞IO的效率快上很多。

Java本身并不具备磁盘读写的能力,要实现磁盘读写必须调用操作系统提供的函数,即从Java方法切换到本地方法。CPU也就会从用户态(Java)切换到内核态(System),其次内存中也有相关的一些操作,当切换到内核态的时候,就可以由CPU的函数真正的读写磁盘文件的内容,从磁盘文件读取进来,因为在内核态的时候使用的是系统内存,所以在读取完成后,会在系统内存中划出一块缓冲区用来存放读取的文件,利用缓冲区分次读取,但是系统缓冲区对于Java代码是不能运行的,所以Java会在Java堆内存中划分一块Java的缓冲区。Java代码要访问刚刚读取流中的数据,必须要从系统缓冲区间接的再读入到Java缓冲区中,Java缓冲区到了Java下一个状态就调用其他的写入操作等。反复反复的进行读写才将目标文件复制到目标位置。很容易发现有一个问题,两个内存两块缓冲区,系统内存有个缓冲区,Java内存有个缓冲区,读取的时候必会让数据存两份,第一次先读到系统缓冲区,然后再由系统缓冲区读取到Java缓冲区中,这样就照成了不要的数据复制,效率因而不是很高。

而使用直接内存之后的效果却有很大的不一样。当我们调用ByteBuffer的allocateDirect方法的时候,就会直接分配一块直接内存,这个方法调用以后,就会在操作系统这边划出一块缓冲区就是下图的Direct memory,划出的这块缓冲区最大的特点就是Java代码可以直接访问,换句话说,这个块内存,Java和系统都可以使用它,它是一个对两块都共享的内存区域。磁盘文件读写的时候,会直接把它读写到Dirct memory中,Java代码就可以直接从缓冲区读取数据,就比上面的方式少了一次缓冲区数据的复制操作所以速度就得到了成倍的提升。

 

直接内存是不会受到JVM的内存回收管理,所以直接内存会存在内存溢出的问题。垃圾回收在Java中对无用对象的释放是自动的,不需要我们手动的调用任何方法,但是直接内存不同,它必须由我们主动来调用Unsafe类中的freeMemory方法才能完成对内存的释放。ByteBuffer中就关联了Unsafe类,在调用ByteBuffer的allocateDirect方法时,其实其实现就是通过Unsafe的allocateMemory和setMemory两个方法来完成对直接内存的分配。那么什么时候又会调用Unsafe的freeMemory方法呢?因为我们说直接内存的释放是通过Unsafe的freeMemory方法实现,这里面的关键在于Cleaner。

ByteBuffer的allocateDirect方法的底层​​​​​

 

关于Cleaner首先看后面的回调任务对象Deallocator(实现了Runable接口),这个回调任务对象中的run方法中就调用了Unsafe的freeMemory方法,从而也验证了直接内存必须由Unsafe对象来释放。

回调任务对象Deallocator

对于Cleaner在Java类库中属于一个特殊的类型——虚引用类型。它的特点是当它关联的对象被回收时,就会触发虚引用的一个Clean方法。在ByteBuffer的allocateDirect方法的底层​​​​​中我们可以看到Cleaner其实与DirectByteBuffer所关联,而DirectByteBuffer是Java对象,所以在DirectByteBuffer对象被垃圾回收的时候,就会执行我们任务对象的run方法。

Cleaner对象的Clean方法

 

 但是直接内存的释放会有一个问题,在JVM调优时,一般会把显示回收禁止掉(即System.gc()无效),因为显示回收其实就是一个Full GC,不管是新生代还是老年代都会统统释放掉,会造成程序暂停的时间比较长,所以为了防止这种情况,JVM调优时就会加上-XX:+DisableExplicitGC的参数来禁用显示回收。这样加上就会影响直接内存的释放机制,因为像ByteBuffer这种对象再内存充足的情况下,是不会进行回收的,所以就会一直占用直接内存。为了解决这种问题,可以采用手动的释放直接内存,即直接调用Unsafe的freeMemory方法,手动调用直接内存的分配和释放。

猜你喜欢

转载自blog.csdn.net/qq_35363507/article/details/104546910