第十一章:直接内存(Direct Memory)

一、直接内存概述

  1、不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。 

  2、直接内存是在Java堆外的、直接向系统申请的内存区间;

  3、来源于NIO,通过存在堆中的 DirectByteBuffer 操作 Native 内存;

  4、通常,访问直接内存的速度会优于 Java 堆。即读写性能高;

    因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存;

    Java的NIO库允许Java程序使用直接内存,用于数据缓冲区。

直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,它直接从操作系统中分配,因此不受Java堆大小的限制,但是会受到本机总内存的大小及处理器寻址空间的限制,因此它也可能导致OutOfMemoryError异常出现。在JDK1.4中新引入了NIO机制,它是一种基于通道与缓冲区的新I/O方式,可以直接从操作系统中分配直接内存,即在堆外分配内存,这样能在一些场景中提高性能,因为避免了在Java堆和Native堆中来回复制数据。

二、访问直接内存的速度会优于 Java 堆

  1、非直接缓冲区(传统IO)

      

    读写文件,需要与磁盘交互,需要由用户态切换到内核态。在内核态时,需要内存如上图的操作。
    使用IO,见上图。这里需要两份内存存储重复数据,效率低。

  2、直接缓冲区(NIO)

    

    使用NIO时,如上图。操作系统划出的直接缓存区可以被 java 代码直接访问,只有一份。NIO适合对大文件的读写操作。

    因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存;

    代码示例:

 1 public class BufferTest {
 2     private static final int BUFFER = 1024 * 1024 * 1024;//1GB
 3 
 4     public static void main(String[] args){
 5         //直接分配本地内存空间
 6         ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
 7         System.out.println("直接内存分配完毕,请求指示!");
 8 
 9         Scanner scanner = new Scanner(System.in);
10         scanner.next();
11 
12 
13         System.out.println("直接内存开始释放!");
14         byteBuffer = null;
15         System.gc();
16         scanner.next();
17     }
18 }

三、直接内存的OOM与大小设置

  1、也可能导致outofMemoryError异常(Direct buffer memory)

  2、由于直接内存在Java堆外,因此它的大小不会直接受限于-Xmx 指定的最大堆大小,但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统能给出的最大内存。

  3、缺点
    ① 分配回收成本较高

    ② 不受 JVM 内存回收管理

  4、直接内存大小可以通过MaxDirectMemorysize设置

  5、如果不指定,默认与堆的最大值 -Xmx 参数值一致

  设置本地内存:

 1 本地内存的OOM:  OutOfMemoryError: Direct buffer memory
 2 public class BufferTest2 {
 3     private static final int BUFFER = 1024 * 1024 * 20;//20MB
 4 
 5     public static void main(String[] args) {
 6         ArrayList<ByteBuffer> list = new ArrayList<>();
 7 
 8         int count = 0;
 9         try {
10             while(true){
11                 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
12                 list.add(byteBuffer);
13                 count++;
14                 try {
15                     Thread.sleep(100);
16                 } catch (InterruptedException e) {
17                     e.printStackTrace();
18                 }
19             }
20         } finally {
21             System.out.println(count);
22         }
23 
24 
25     }
26 }

     

   简单理解:

  Java process memory = java heap + native memory

更多:

  堆外内存

  Direct Memory(堆外内存)

  

 

原文地址:https://www.cnblogs.com/niujifei/p/14664978.html