JVM(HotSpot):直接内存及其使用建议

文章目录

一、什么是直接内存?

Direct Memory:系统内存

普通IO,运行原理图

磁盘到系统内存,系统内存到jvm内存。

NIO,运行原理图

划分了一块区域,JVM和系统共享的内存区间,这样,就减少了一次IO操作。

二、特点

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

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

不受 JVM 内存回收管理

所以,我们可以在IO程序中,使用直接内存来优化程序的读写性能。

三、使用案例

关键代码:ByteBuffer.allocateDirect(_1Mb);

java 复制代码
public class Demo1_9 {
    static final String FROM = "E:\\sbPSjI4tt10.mp4";
    static final String TO = "E:\\a.mp4";
    static final int _1Mb = 1024 * 1024;

    public static void main(String[] args) {
        io(); // io 用时:1535.586957 1766.963399 1359.240226
        directBuffer(); // directBuffer 用时:479.295165 702.291454 562.56592
    }

    private static void directBuffer() {
        long start = System.nanoTime();
        try (FileChannel from = new FileInputStream(FROM).getChannel();
             FileChannel to = new FileOutputStream(TO).getChannel();
        ) {
            ByteBuffer bb = ByteBuffer.allocateDirect(_1Mb);
            while (true) {
                int len = from.read(bb);
                if (len == -1) {
                    break;
                }
                bb.flip();
                to.write(bb);
                bb.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.nanoTime();
        System.out.println("directBuffer 用时:" + (end - start) / 1000_000.0);
    }

    private static void io() {
        long start = System.nanoTime();
        try (FileInputStream from = new FileInputStream(FROM);
             FileOutputStream to = new FileOutputStream(TO);
        ) {
            byte[] buf = new byte[_1Mb];
            while (true) {
                int len = from.read(buf);
                if (len == -1) {
                    break;
                }
                to.write(buf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.nanoTime();
        System.out.println("io 用时:" + (end - start) / 1000_000.0);
    }
}

但是,直接内存,是不受JVM管理的

另外,我们显示调用gcJVM也不是立马就执行gc

而且,一般我们会在项目中禁用显示调用gc,因为,Full GC影响性能。

禁用参数:-XX:+DisableExplicitGC

四、直接内存的管理

底层是如何回收直接内存的?

  • 使用了 Unsafe 对象完成直接内存的分配回收,并且回收需要主动调用 freeMemory 方法
  • ByteBuffer 的实现类内部,使用了 Cleaner (虚引用)来监测 ByteBuffer 对象,一旦
    ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleanerclean 方法调
    freeMemory 来释放直接内存

    我们知道,不建议程序员显示调用gc,来回收JVM对象。
    但是,等待JVM自主的Full GC,又是不确定的。
    所以,还是,建议我们自己手动回收直接内存。
java 复制代码
public class Demo1_27 {
    static int _1Gb = 1024 * 1024 * 1024;

    public static void main(String[] args) throws IOException {
        Unsafe unsafe = getUnsafe();
        // 分配内存
        long base = unsafe.allocateMemory(_1Gb);
        unsafe.setMemory(base, _1Gb, (byte) 0);
        System.in.read();

        // 释放内存
        unsafe.freeMemory(base);
        System.in.read();
    }

    public static Unsafe getUnsafe() {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe = (Unsafe) f.get(null);
            return unsafe;
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}
相关推荐
Shorasul几秒前
如何修改数据库实例名_ORACLE_SID环境变量重命名实战
jvm·数据库·python
2301_8035389515 分钟前
如何在 Go 中精确安装指定版本的模块.txt
jvm·数据库·python
Greyson116 分钟前
如何利用RMAN修复逻辑坏块_VALIDATE CHECK LOGICAL验证块内结构损坏
jvm·数据库·python
m0_6403093032 分钟前
如何在phpMyAdmin中生成XML格式导出_与其他企业系统的数据交互
jvm·数据库·python
2301_8152795239 分钟前
JavaScript中快速清空数组的多种方式及其性能差异
jvm·数据库·python
2402_854808371 小时前
CSS如何实现元素在容器内居中_利用margin-auto技巧
jvm·数据库·python
weixin_580614001 小时前
html标签怎么表示用户输入_kbd标签键盘快捷键标注【介绍】
jvm·数据库·python
m0_716430071 小时前
如何监控集群 interconnect_ping与traceroute验证心跳通畅.txt
jvm·数据库·python
m0_678485451 小时前
如何通过 curl 调用 Go 标准库 RPC 服务(JSON-RPC 协议)
jvm·数据库·python
极客on之路1 小时前
线上 JVM 出问题
运维·服务器·jvm