7 直接内存

7 直接内存

7.1 定义和介绍

直接内存属于系统内存,并不属于jvm。属于操作系统内存管理。

  • 常见于BIO操作时,用于数据缓冲区

  • 分配回收成本较高,但读写性能高

  • 不受JVM内存回收管理

使用传统的io和使用直接内存读取一个800M大小的文件对比

 

 

思考:为什么使用直接内存,我们大文件的读写效率会这么高?

先了解文件读写过程,java要调用操作系统提供函数才能读写。那么cpu的状态会从用户态变为内核态。当切换到内核态的时候,由cpu的函数去读取磁盘文件内容。他会在操作系统内存中划出一块系统缓冲区,磁盘的内容会先读到这个系统缓冲区。不肯把800M的东西直接读到内存,那内存会顶不住。利用缓冲区分次读取。注意系统缓冲器java不能读取,所以java在堆区划分一块java缓冲区,要想读取到数据,就把数据从系统缓冲区读到java缓冲区。之后cpu进入用户态,去调用输出流的写入操作,反复读写把文件复制。

 

 

现在发现了问题:有2块缓冲区,那读取的时候数据会存两份。这样造成不必要的数据复制,效率低。

如果使用直接内存:当我们调用allocateDirect(_1Mb),分配一块直接内存,代表着我会 在操作系统划出一块直接内存区,这块内存系统可以直接用,java代码也可以直接用,是共享的。比刚才的少一次缓冲区复制操作 ,效率提高。

 

 

 

7.2 内存溢出

因为不会被JVM管理,GC也回收不到这块内存。那会存在直接内存溢出的情况。

 

 

7.3 内存释放原理

直接内存在底层的分配和释放是通过unsafe管理的,一般jdk内部人员用到unsafe,我们用不着。image-20210919113749745

那么bytebuffer如何和unsafe关联起来的呢?

 

 

后台有一个线程监控着,虚引用机制,如果没人用直接内存了,那就主动执行任务去释放直接内存。

 

 

 

7.4 禁用显示回收对直接内存的影响

 

 

我们在JVM调优的时候,通常会加这句,让我们GC不工作

 -XX:+DisableExplicitGC

System.GC()他不仅会回收新生代,还会回收老年代,造成程序暂停的时间比较长。为了防止一些程序员不小心写system.GC()触发垃圾回收影响性能。

一旦禁用system.GC()以后啊,那我们bytebuffer关联的直接内存也不会被释放掉。造成直接内存长时间占用。那怎么办呢?

可以用unsafe对象去调用freeMemory去释放直接内存

 

 

手动管理这块直接内存

posted on 2021-10-12 10:28  Love&Share  阅读(193)  评论(0编辑  收藏  举报

导航