随笔 - 1162  文章 - 0  评论 - 16  阅读 - 59万 

一、直接内存概述

  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(堆外内存)

  

 

posted on   格物致知_Tony  阅读(1074)  评论(0编辑  收藏  举报
编辑推荐:
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
点击右上角即可分享
微信分享提示

目录导航