Skip to content

Latest commit

 

History

History
202 lines (116 loc) · 5.13 KB

23.学习盛宴:NIO的DirectByteBuffer核心原理.md

File metadata and controls

202 lines (116 loc) · 5.13 KB

23 学习盛宴:NIO的DirectByteBuffer核心原理

再介绍UnpooledDirectByteBuf之前,先了解一下NIO的DirectByteBuffer.

  public static void main(String[] args) {
        System.setProperty("java.jvm.name", "XXXX");
//        UnpooledDirectByteBuf unpooledDirectByteBuf = (UnpooledDirectByteBuf) UnpooledByteBufAllocator.DEFAULT.directBuffer(9, 100);
        ByteBuf byteBuf = UnpooledByteBufAllocator.DEFAULT.directBuffer(9, 100);
        System.err.println(byteBuf);
    }

通过debug我们发现,UnpooledByteBufAllocator底层是jdk的DirectByteBuffer

什么是JDK的DirecrByteBuffer?

直接内存和JVM堆内存之间有什么区别?

public class DirectByteBufferTest {

    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocateDirect(20);

        for (byte i = 0; i < 5; i++){
            buffer.put(i);
        }

        buffer.flip();

        for (byte i = 0; i < 5; i++){
            System.err.println(i);
        }
    }
}

测试结果如下:

0
1
2
3
4

DirectByteBuffer的继承关系

DirectByteBuffer的创建方法

DirectByteBuffer的优势

为什么创建和回收直接内存的性能比较低?

查看直接内存的大小

		long l = VM.maxDirectMemory();
        System.err.println(l / 1024 / 1024);

        long l1 = Runtime.getRuntime().maxMemory();
        System.err.println(l1 / 1024/ 1024);

默认情况下,直接内存大小和设置的对内存大小是一致的。。

这块是加了一份Survivor区域。

如何设置直接内存的大小

-XX:MaxDirectMemorySize=1024M

DirectByteBuffer的构造函数

DirectByteBuffer(int cap) {                   // package-private

        super(-1, 0, cap, cap);
        boolean pa = VM.isDirectMemoryPageAligned();
        int ps = Bits.pageSize();
        long size = Math.max(1L, (long)cap + (pa ? ps : 0));
        Bits.reserveMemory(size, cap);

        long base = 0;
        try {
            base = unsafe.allocateMemory(size);
        } catch (OutOfMemoryError x) {
            Bits.unreserveMemory(size, cap);
            throw x;
        }
        unsafe.setMemory(base, size, (byte) 0);
        if (pa && (base % ps != 0)) {
            // Round up to page boundary
            address = base + ps - (base & (ps - 1));
        } else {
            address = base;
        }
        cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
        att = null;
    }

上面还做了一些内存对齐的工作。。

DirectByteBuffer内存的回收

Cleaner对象进行内存回收的缺点是存在滞后性。

使用unsafe.freememory 方法释放直接内存

注意这里分配内存的构造器也发生了变化,因为使用默认的构造器,会额外创建cleaner对象。
这也是netty底层优先使用的方法。

什么是Unsafe类

Unsafe类中关于内存操作的几个方法

上面这几个方法创建的都是用户空间的内存,也就是直接内存,不是堆内存!

使用堆外内存的原因

什么情况下使用到堆外内存

对象池和内存池

堆外内存的特点

  • 对于大内存有良好的伸缩性
  • 明显提升了垃圾回收的停顿
  • 在进程间可以共享,避免了虚拟机之间的复制

堆外内存存在的一些问题

小结