zoukankan      html  css  js  c++  java
  • [编织消息框架][netty源码分析]10 ByteBuf 与 ByteBuffer

    因为jdk ByteBuffer使用起来很麻烦,所以netty研发出ByteBuf对象维护管理内存
    使用ByteBuf有几个概念需要知道
    1.向ByteBuf提取数据时readerIndex记录最后读取坐标,目的是下次从readerIndex开始读
    2.向ByteBuf写入数据时writerIndex记录最后写数据坐标
    3.提取数据范围是readerIndex<=writerIndex,因为先写入数据然后才能读取数据
    4.自动扩容,当writerIndex达到一定阈值时,会扩大capacity

    所以ByteBuf只需要维护readerIndex,writerIndex记录就能简化jdk提供的ByteBuffer api
    分析ByteBuf有几个疑问
    1.ByteBuf是如何扩容的,扩容后已读的数据如何减少或容量缩少
    2.ByteBuf是如何创建、维护的

    在分析之前先了解java分配内存有几种方式
    1.HeapByteBuffer是分配在堆上的,直接由Jvm负责垃圾收集,你可以把它想象成一个字节数组的包装类
    2.DirectByteBuffer是通过JNI在Jvm外的内存中分配了一块,该内存块并不直接由jvm负责垃圾收集,
    但是在DirectByteBuffer包装类被回收时,会通过Java Reference机制来释放该内存块,也可手动调用clean回收
    Direct空间大小通过设置JVM参数-Xmx,如果没设置-XX:MaxDirectMemorySize,则默认与-Xmx参数值相同
    3.MappedByteBuffer是高效处理文件I/O,实现子类是DirectByteBuffer,里面维护了一个address是逻辑地址,通过FileChannel提供map方法把文件映射到虚拟内存,通常情况可以映射整个文件
    对MappedByteBuffer兴趣的读者可以阅读 http://www.jianshu.com/p/f90866dcbffc

    public abstract class ByteBuffer
        extends Buffer
        implements Comparable<ByteBuffer>
    {
        final byte[] hb;                  // Non-null only for heap buffers
        final int offset;
        boolean isReadOnly;                 // Valid only for heap buffers
    
        ByteBuffer(int mark, int pos, int lim, int cap,
                     byte[] hb, int offset)
        {
            super(mark, pos, lim, cap);
            this.hb = hb;
            this.offset = offset;
        }
        //创建直接内存
        public static ByteBuffer allocateDirect(int capacity) {
            return new DirectByteBuffer(capacity);
        }
        //创建heap内存
        public static ByteBuffer allocate(int capacity) {
            if (capacity < 0)
                throw new IllegalArgumentException();
            return new HeapByteBuffer(capacity, capacity);
        }
    }
    import java.lang.reflect.Field;
    import java.nio.ByteBuffer;
    import java.util.concurrent.TimeUnit;
    
    import sun.nio.ch.DirectBuffer;
    
    public class DirectByteBufferTest {
        public static void main(String[] args) throws InterruptedException {
            testa();
            testb();
        }
    
        private static void testa() throws InterruptedException {
            printlnDirectInfo("test a");
            // 分配512MB直接缓存
            ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 * 512);
            printlnDirectInfo("init");
            // 清除直接缓存
            ((DirectBuffer) bb).cleaner().clean();
            TimeUnit.SECONDS.sleep(2);
            printlnDirectInfo("clear");
            System.out.println("end");
         }
            
         private static void testb() throws InterruptedException {
            printlnDirectInfo("test b");
            // 分配512MB直接缓存
            ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 * 512);
            printlnDirectInfo("init");
            // 删除引用
            bb=null;
            System.gc();
            TimeUnit.SECONDS.sleep(2);
            printlnDirectInfo("clear");
            System.out.println("end");
        }
    
        private static void printlnDirectInfo(String tag) {
            try {
                Class<?> c = Class.forName("java.nio.Bits");
                Field field1 = c.getDeclaredField("maxMemory");
                field1.setAccessible(true);
                Field field2 = c.getDeclaredField("reservedMemory");
                field2.setAccessible(true);
                synchronized (c) {
                Object max = (Object) field1.get(null);
                Object reserve = (Object) field2.get(null);
                System.out.println(tag + " ##### " +max + " " + reserve);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    小结:

    DirectByteBuffer 是分配是堆外的,所以创建跟回收是比较占CPU时间,如果对象生命周期短不建议放在DirectByteBuffer

    HeapByteBuffer 是分配是堆内的,回收很快,但频烦创建大量对象无疑增加GC回收次数

    netty有基于Heap实现UnpooledHeapByteBuf,也有Direct实现UnpooledDirectByteBuf

    还有内存池PooledByteBuf这种黑科技,之所有出现这么多实现是参照jdk的设计,目的是降低api复杂、方便维护、减少创建回收频率

    了解jdk ByteBuffer 内存分配有几种方式同使用场景,直接内存如果不手动回收的话一定要注意引用否则会出现内存泄漏

  • 相关阅读:
    js提交表单错误:document.form.submit() is not a function
    eclipse中把多个项目放在一个work set下
    SpringMVC源码分析系列
    java.util.ConcurrentModificationException详解
    java动态代理(JDK和cglib)代码完整版本
    java静态代理和动态代理
    看完这5张图!不同类型停车位的停车技巧get!
    记住这6个方法,让你的车辆轻松过年检!
    B样条 理论基础
    virtual studio 主题更换
  • 原文地址:https://www.cnblogs.com/solq111/p/7086300.html
Copyright © 2011-2022 走看看