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

目录

直接内存(Direct Memory)

直接缓存区

代码实现

最后


直接内存(Direct Memory)

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

非直接缓存区

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

直接缓存区

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

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

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

代码实现

非直接缓冲区

/**
 * @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();
    }
}

释放前

释放后

模拟直接内存溢出

/**
 * @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();
        }
    }
}

结果

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虚拟机》 –周志明

往期推荐

怎么样学习java最快?

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

spring整合各种中间件(RocketMQ、kafka、RabbitMQ、ActiveMQ、ZeroMQ)-ZeroMQ

逃逸分析(Escape Analysis)技术

spring整合中间件(RocketMQ、kafka、RabbitMQ、ActiveMQ、ZeroMQ)ActiveMQ

jvm堆

spring整合中间件(RocketMQ、kafka、RabbitMQ)-RabbitMQ

RabbitMQ基于windows10安装

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐