[Netty源码分析]ByteBuf(二)

  1. ByteBufAllocator

ByteBufAllocator是字节缓冲区分配器,根据Netty字节缓冲区的实现不同,分为两种不同的分配器PooledByteBufAllocator和UnpooledByteBufAllocator。他们提供了不同ByteBuf的分配方法

ByteBufAllocator 继承体系.png

API分类:

  1. buffer*前缀为分配普通 buffer;

  2. ioBuffer*前缀为分配适用于 I/O 操作的 buffer;

  3. directBuffer*前缀为分配直接内存 buffer;

  4. composite*前缀为分配合成 buffer;

Q:heapBuffer和directBuffer就是分配堆内内存和堆外内存了,为什么还要上面的buffer方法?后面的AbstractByteBufAllocator就解释分配内存时先调用buffer方法,再在这个方法里面地调用heapBufffer和directBuffer

ByteBufAllocator的buffer:

/**
   * Allocate a {@link ByteBuf}. If it is a direct or heap buffer
   * depends on the actual implementation.
   */
  ByteBuf buffer();

  ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  //AbstractByteBufAllocator
  @Override
  public ByteBuf buffer() {
      if (directByDefault) {
          return directBuffer();
      }
      return heapBuffer();
  }

  →→→→→ directBuffer具体实现
  @Override
  public ByteBuf directBuffer() {
      return directBuffer(DEFAULT_INITIAL_CAPACITY, Integer.MAX_VALUE);
  }

  ↓↓↓↓↓↓↓↓↓↓
  @Override
  public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
      if (initialCapacity == 0 && maxCapacity == 0) {
          return emptyBuf;
      }
      validate(initialCapacity, maxCapacity);
      return newDirectBuffer(initialCapacity, maxCapacity);
  }

  ↓↓↓↓↓↓↓↓↓↓
  /**
   * 依赖底层实现.
   */
  protected abstract ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity);

  →→→→→ heapBuffer具体实现
  @Override
  public ByteBuf heapBuffer() {
      return heapBuffer(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_CAPACITY);
  }

  ↓↓↓↓↓↓↓↓↓↓
  @Override
  public ByteBuf heapBuffer(int initialCapacity, int maxCapacity) {
      if (initialCapacity == 0 && maxCapacity == 0) {
          return emptyBuf;
      }
      validate(initialCapacity, maxCapacity);
      return newHeapBuffer(initialCapacity, maxCapacity);
  }

  ↓↓↓↓↓↓↓↓↓↓↓
  /**
   * 依赖底层实现.
   */
  protected abstract ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity);
  1. PooledByteBufAllocator和UnpooledByteBufAllocator
  1. Heap内存分配
    //UnpooledByteBufAllocator的newDirectBuffer和newHeapBuffer
    @Override
    protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
        ByteBuf buf;
        //是否unsafe是由jdk底层去实现的,如果能够获取到unsafe对象,就使用unsafe
        if (PlatformDependent.hasUnsafe()) {
            buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
        } else {
            buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
        }
        return toLeakAwareBuffer(buf);
    }

    @Override
    protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
        //Netty5不区分安全与非安全
        return new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
        //Netty4的实现如下:
        //return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity)
                : new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
    }

    ↓↓↓↓↓↓↓↓↓↓↓↓↓Netty5对UnpooledHeapByteBuf的实现
    public UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
        super(maxCapacity);
        checkNotNull(alloc, "alloc");
        if (initialCapacity > maxCapacity) {
            throw new IllegalArgumentException(String.format(
                    "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
        }
        this.alloc = alloc;
        setArray(allocateArray(initialCapacity));
        setIndex(0, 0);
    }

    ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    //AbstractReferenceCountedByteBuf
    protected AbstractReferenceCountedByteBuf(int maxCapacity) {
        super(maxCapacity);
        refCntUpdater.set(this, 1);
    }

    ↓↓↓↓↓↓↓↓↓↓↓↓↓Netty4对UnpooledUnsafeHeapByteBuf的实现
    //UnpooledUnsafeHeapByteBuf
    UnpooledUnsafeHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
        super(alloc, initialCapacity, maxCapacity);
    }

    ↓↓↓↓↓↓↓↓↓↓↓↓↓
    //UnpooledHeapByteBuf
    protected UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
        this(alloc, new byte[initialCapacity], 0, 0, maxCapacity);
    }

    //再跳回原来的UnpooledHeapByteBuf
    private UnpooledHeapByteBuf(
            ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) {
          //略
    }

    ↓↓↓↓↓↓↓↓↓↓↓↓↓保存字节数据和指针
    private void setArray(byte[] initialArray) {
        array = initialArray;
        tmpNioBuf = null;
    }

    @Override
    public ByteBuf setIndex(int readerIndex, int writerIndex) {
        if (readerIndex < 0 || readerIndex > writerIndex || writerIndex > capacity()) {
            throw new IndexOutOfBoundsException(String.format(
                    "readerIndex: %d, writerIndex: %d (expected: 0 <= readerIndex <= writerIndex <= capacity(%d))",
                    readerIndex, writerIndex, capacity()));
        }
        setIndex0(readerIndex, writerIndex);
        return this;
    }

    //安全和非安全看这里,Nett5和Netty4的newHeapBuffer不一样了,以下举例Netty4:
    //UnpooledHeapByteBuf
    @Override
    protected byte _getByte(int index) {
        return HeapByteBufUtil.getByte(array, index);
    }

    ↓↓↓↓↓↓↓↓↓
    //HeapByteBufUtil
    static byte getByte(byte[] memory, int index) {
        return memory[index];
    }

    //UnpooledUnsafeHeapByteBuf
    @Override
    protected byte _getByte(int index) {
        return UnsafeByteBufUtil.getByte(array, index);
    }

    ↓↓↓↓↓↓↓↓↓↓↓↓
    //UnsafeByteBufUtil
    static byte getByte(long address) {
        return PlatformDependent.getByte(address);
    }
  1. direct内存分配
//UnpooledDirectByteBuf
public UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
    super(maxCapacity);
    if (alloc == null) {
        throw new NullPointerException("alloc");
    }
    if (initialCapacity < 0) {
        throw new IllegalArgumentException("initialCapacity: " + initialCapacity);
    }
    if (maxCapacity < 0) {
        throw new IllegalArgumentException("maxCapacity: " + maxCapacity);
    }
    if (initialCapacity > maxCapacity) {
        throw new IllegalArgumentException(String.format(
                "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
    }

    this.alloc = alloc;
    setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));
}

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
private void setByteBuffer(ByteBuffer buffer) {
      ByteBuffer oldBuffer = this.buffer;
      if (oldBuffer != null) {
          if (doNotFree) {
              doNotFree = false;
          } else {
              freeDirect(oldBuffer);
          }
      }
      this.buffer = buffer;
      tmpNioBuf = null;
      capacity = buffer.remaining();
  }

  →→→→→→JDK底层方法ByteBuffer.allocateDirect(initialCapacity)
  //ByteBuffer
  public static ByteBuffer allocateDirect(int capacity) {
      return new DirectByteBuffer(capacity);
  }

  //
  public UnpooledUnsafeDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
      super(maxCapacity);
      if (alloc == null) {
          throw new NullPointerException("alloc");
      }
      if (initialCapacity < 0) {
          throw new IllegalArgumentException("initialCapacity: " + initialCapacity);
      }
      if (maxCapacity < 0) {
          throw new IllegalArgumentException("maxCapacity: " + maxCapacity);
      }
      if (initialCapacity > maxCapacity) {
          throw new IllegalArgumentException(String.format(
                  "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
      }

      this.alloc = alloc;
      //allocateDirect(initialCapacity)同调用JDK的API
      setByteBuffer(allocateDirect(initialCapacity), false);
  }

  ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  //非安全的区别在于通过反射UnSafe算出内存地址保存memoryAddress
  final void setByteBuffer(ByteBuffer buffer, boolean tryFree) {
      if (tryFree) {
          ByteBuffer oldBuffer = this.buffer;
          if (oldBuffer != null) {
              if (doNotFree) {
                  doNotFree = false;
              } else {
                  freeDirect(oldBuffer);
              }
          }
      }
      this.buffer = buffer;
      memoryAddress = PlatformDependent.directBufferAddress(buffer);
      tmpNioBuf = null;
      capacity = buffer.remaining();
  }

  →→→→→→→→→→→→
  //getByte的时候通过地址去找
  @Override
  protected byte _getByte(int index) {
      return UnsafeByteBufUtil.getByte(addr(index));
  }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容