Skip to content
文章目录

1、直接内存是什么?

  • 直接内存是一块由操作系统直接管理的内存,也叫对外内存,IO效率较高
  • 可以使用Unsafe或ByteBuffer分配直接内存
    • Unsafe
      • 溢出时报:java.lang.OutOfMemoryError
      • -XX:MaxDirectMemorySize不起作用
    • ByteBuffer
      • 溢出时报:java.lang.OutOfMemoryError:Direct buffer memory
      • -XX:MaxDirectMemorySize起作用
      • ByteBuffer底层也是Unsafe去分配内存
  • 可用-XX:MaxDirectMemorySize控制,默认是0,表示不限制

2、为什么要用直接内存?

3、使用场景

  • 有很大的数据需要存储,生命周期很长
  • 频繁的IO操作,如并发网络通信

4、分配直接内存

  • Unsafe.allocatememory(size)
  • ByteBuffer.allocateDirect(size)
java
package com.zhz.jvm.tuning;


import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class DirectMemoryTest1 {
    private static final int MB_1 = 1024 * 1024;

    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
        //通过反射获取Unsafe类并通过其分配直接内存
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);

        // 分配1M内存,并返回这块内存的起始地址
        long address = unsafe.allocateMemory(MB_1);

        // 向内存地址中设置对象
        unsafe.putByte(address, (byte) 1);

        // 从内存中获取对象
        byte aByte = unsafe.getByte(address);
        System.out.println(aByte);

        // 释放内存
        unsafe.freeMemory(address);
    }
}
java
package com.zhz.jvm.tuning;

import java.nio.ByteBuffer;

public class DirectMemoryTest2 {
    private static final int ONE_MB = 1024 * 1024;

    /**
     * ByteBuffer参考文档:
     * https://blog.csdn.net/z69183787/article/details/77102198/
     *
     * @param args args
     */
    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocateDirect(ONE_MB);
        // 相对写,向position的位置写入一个byte,并将postion+1,为下次读写作准备
        buffer.put("abcde".getBytes());
        buffer.put("fghij".getBytes());

        // 转换为读取模式
        buffer.flip();

        // 相对读,从position位置读取一个byte,并将position+1,为下次读写作准备
        // 读取第1个字节(a)
        System.out.println((char) buffer.get());

        // 读取第2个字节
        System.out.println((char) buffer.get());

        // 绝对读,读取byteBuffer底层的bytes中下标为index的byte,不改变position
        // 读取第3个字节
        System.out.println((char) buffer.get(2));

    }
}
java
package com.zhz.jvm.tuning;//package com.imooc.jvminaction;


import sun.misc.Unsafe;

import java.lang.reflect.Field;

// 1. Unsafe导致直接内存溢出报错没有小尾巴
// 2. -XX:MaxDirectMemorySize=100m对Unsafe不起作用
public class DirectMemoryTest3 {
    private static final int GB_1 = 1024 * 1024 * 1024;

    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
        //通过反射获取Unsafe类并通过其分配直接内存
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);

        int i = 0;
        while (true) {
            unsafe.allocateMemory(GB_1);
            System.out.println(++i);
        }
    }
}
java
package com.zhz.jvm.tuning;

import java.nio.ByteBuffer;

// 1. ByteBuffer直接内存溢出报错是java.lang.OutOfMemoryError: Direct buffer memory
// 2. -XX:MaxDirectMemorySize对ByteBuffer有效
public class DirectMemoryTest4 {
    private static final int GB_1 = 1024 * 1024 * 1024;

    /**
     * ByteBuffer参考文档:
     * https://blog.csdn.net/z69183787/article/details/77102198/
     *
     * @param args args
     */
    public static void main(String[] args) {
        int i= 0;
        while (true) {
            ByteBuffer buffer = ByteBuffer.allocateDirect(GB_1);
            System.out.println(++i);
        }
    }
}

5、直接内存经验之说

  • 堆Dump文件看不出问题或者比较小,可考虑直接内存溢出问题
  • 配置内存时,应给直接内存预留足够的空间