前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM-直接内存(Direct Memory)

JVM-直接内存(Direct Memory)

作者头像
逍遥壮士
发布2021-07-05 19:01:50
1.3K0
发布2021-07-05 19:01:50
举报
文章被收录于专栏:技术趋势技术趋势

上文:对象实例化与内存布局(深入)

直接内存(Direct Memory)

直接内存是Java堆之外的,直接向系统申请的内存空间,所以直接内存不是虚拟机的一部分,也不是《Java虚拟机规范》中定义的内存区域,也有可能导致OOM。

非直接缓存区

在jdk1.4之前,java的对象与系统之间的交互如下图,先从JVM需要从用户态切换到内核态时,这样的话读取或写入一份数据需要经历四个步骤:jvm切换到内核态缓冲区读取->操作系统将数据拷贝用户缓冲区-->-再次切换到内核态并将用户缓存区数据拷贝进来->将内核态缓冲区写入socket buffer(cpu参与两次)

直接缓存区

直接内存也称直接缓存区,主要是解决一个java读取慢的问题,jdk1.4以后jvm 引入了NIO在操作系统划出了一块直接的缓存区可以直接被java访问。就是所称的零拷贝。

用户->内核态缓冲区(cpu不参与)

零拷贝文章什么是零拷贝(Zero-copy)?

代码实现

非直接缓冲区

代码语言:javascript
复制
/**
 * @author: csh
 * @Date: 2021/5/8 18:49
 * @Description:非直接缓存冲(堆内存)
 */
public class ByteBufferTest {
    public static void main(String[] args) {
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024*1024*1024);
        System.out.println("开始分配内存");

        Scanner scanner = new Scanner(System.in);
        scanner.next();

        System.out.println("直接内存开始释放");
        byteBuffer=null;
        System.gc();
        scanner.next();
    }
}

释放前

释放后

模拟直接内存溢出

代码语言:javascript
复制
/**
 * @author: csh
 * @Date: 2021/5/13 18:37
 * @Description:OOM 模拟直接内存溢出
 *
 * Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
 */
public class BufferTest2 {

    private static final int BUFFER =1024 * 1024 * 20;

    public static void main(String[] args) {
        ArrayList<ByteBuffer> list = new ArrayList <>();
        int count = 0;
        try {
            while (true){
                ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
                list.add(byteBuffer);
                Thread.sleep(100);
            }
        }catch (Exception e){
            System.out.println("总共打印");
            e.printStackTrace();
        }
    }
}

结果

代码语言:javascript
复制
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
  at java.nio.Bits.reserveMemory(Bits.java:694)
  at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
  at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
  at com.memory.BufferTest2.main(BufferTest2.java:22)

最后

不管是直接内存还是传统的内存,都有利有弊,比如直接内存可以尽大限度的拓展内存空间,但是一但发生oom那排查起来非常麻烦,因为这块控制是非常难的,并且只有当full gc才会被回收,当然也是可以通过:通过-XX:MaxDirectMemorySize来指定最大的堆外内存大小。直接内存的写入速度没有

参考文章 https://www.cnblogs.com/yy3b2007com/archive/2017/07/31/7262453.html

https://zh.wikipedia.org/w/index.php?title=%E7%9B%B4%E6%8E%A5%E8%A8%98%E6%86%B6%E9%AB%94%E5%AD%98%E5%8F%96&useFormat=mobile&variant=zh-sg

https://my.oschina.net/newchaos/blog/4873863

https://developer.aliyun.com/article/763697

https://zhuanlan.zhihu.com/p/161939673

参考书籍

《深入理解Java虚拟机》 –周志明

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术趋势 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档