netty源码阅读之ByteBuf之内存分配器UnpooledByteBufAllocator

我们从两个角度分析UnpooledByteBufAllocator:

1、heap内存的分配

2、direct内存的分配

由于unpooled就是自己去操作底层api去分配内存,实现起来比较简单。

一、heap内存的分配

上一篇文章其实在最后一部分我们分析过了,heap的的内存分配和读取都是在array数组上面。分配的堆内存源码就是下面UnpooledByteBufAllocator的这一段:


  1. @Override
  2. protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
  3. return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity)
  4. : new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
  5. }

参考上一篇文章第三部分看可以了

二、direct内存的分配

和heap不同,direct内存分配放在buffer里面,然后unsafe的direct buffer是通过底层的unsafe类去操作的。(其实看源码到最终,direct的buffer都是通过unsafe去操作的)

从UnpooledByteBufAllocator分配direct内存的这个源码开始看起:


  1. @Override
  2. protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
  3. ByteBuf buf = PlatformDependent.hasUnsafe() ?
  4. UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :
  5. new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
  6. return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
  7. }

我们先看unsafe吧,从UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) 这里进去:


  1. static UnpooledUnsafeDirectByteBuf newUnsafeDirectByteBuf(
  2. ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
  3. if (PlatformDependent.useDirectBufferNoCleaner()) {
  4. return new UnpooledUnsafeNoCleanerDirectByteBuf(alloc, initialCapacity, maxCapacity);
  5. }
  6. return new UnpooledUnsafeDirectByteBuf(alloc, initialCapacity, maxCapacity);
  7. }

不管nocleaner先,从最后UnpooledUnsafeDirectByteBuf这个函数进去:


  1. /**
  2. * Creates a new direct buffer.
  3. *
  4. * @param initialCapacity the initial capacity of the underlying direct buffer
  5. * @param maxCapacity the maximum capacity of the underlying direct buffer
  6. */
  7. protected UnpooledUnsafeDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
  8. super(maxCapacity);
  9. if (alloc == null) {
  10. throw new NullPointerException("alloc");
  11. }
  12. if (initialCapacity < 0) {
  13. throw new IllegalArgumentException("initialCapacity: " + initialCapacity);
  14. }
  15. if (maxCapacity < 0) {
  16. throw new IllegalArgumentException("maxCapacity: " + maxCapacity);
  17. }
  18. if (initialCapacity > maxCapacity) {
  19. throw new IllegalArgumentException(String.format(
  20. "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
  21. }
  22. this.alloc = alloc;
  23. setByteBuffer(allocateDirect(initialCapacity), false);
  24. }

最后这个allocateDirect(initialCapacity):


  1. /**
  2. * Allocate a new direct {@link ByteBuffer} with the given initialCapacity.
  3. */
  4. protected ByteBuffer allocateDirect(int initialCapacity) {
  5. return ByteBuffer.allocateDirect(initialCapacity);
  6. }

就是调用jdk底层去创建directbytebuffer。

回去setByteBuffer:


  1. final void setByteBuffer(ByteBuffer buffer, boolean tryFree) {
  2. if (tryFree) {
  3. ByteBuffer oldBuffer = this.buffer;
  4. if (oldBuffer != null) {
  5. if (doNotFree) {
  6. doNotFree = false;
  7. } else {
  8. freeDirect(oldBuffer);
  9. }
  10. }
  11. }
  12. this.buffer = buffer;
  13. memoryAddress = PlatformDependent.directBufferAddress(buffer);
  14. tmpNioBuf = null;
  15. capacity = buffer.remaining();
  16. }

把刚刚调用allocateDirect分配的buffer赋值到this.buffer里面去。

注意memoryAddress,从这PlatformDependent.directBufferAddress(buffer);一直进去:


  1. static long directBufferAddress(ByteBuffer buffer) {
  2. return getLong(buffer, ADDRESS_FIELD_OFFSET);
  3. }

也就是,我们获取到内存地址,加上offset,就是我们能用的开始的地址,getLong继续就是:


  1. private static long getLong(Object object, long fieldOffset) {
  2. return UNSAFE.getLong(object, fieldOffset);
  3. }

调用了jdk底层unsafe加上offset为我们获取我们能用的direct地址,最终回来保存到memoryAddress里面。

回到UnpooledUnsafeDirectByteBuf的_getByte方法:


  1. @Override
  2. protected byte _getByte(int index) {
  3. return UnsafeByteBufUtil.getByte(addr(index));
  4. }

看addr(index):


  1. long addr(int index) {
  2. return memoryAddress + index;
  3. }

这个memoryAddress就是上面那个,也就是通过memoryAddress就能操作unsafedirect buffer内存了。

好,这就是UnpooledByteBufAllocator分配和操作direct unsafe内存的分析了

看非unsafe,一样是下面这个代码:


  1. @Override
  2. protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
  3. ByteBuf buf = PlatformDependent.hasUnsafe() ?
  4. UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :
  5. new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
  6. return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
  7. }

从UnpooledDirectByteBuf进入:


  1. private void setByteBuffer(ByteBuffer buffer) {
  2. ByteBuffer oldBuffer = this.buffer;
  3. if (oldBuffer != null) {
  4. if (doNotFree) {
  5. doNotFree = false;
  6. } else {
  7. freeDirect(oldBuffer);
  8. }
  9. }
  10. this.buffer = buffer;
  11. tmpNioBuf = null;
  12. capacity = buffer.remaining();
  13. }

可以看到没有memoryAddress了,只有buffer。在UnpooledDirectByteBuf的_getByte方法里面,就是直接读取buffer里面的内容了:


  1. @Override
  2. protected byte _getByte(int index) {
  3. return buffer.get(index);
  4. }

netty源码阅读之ByteBuf之内存分配器UnpooledByteBufAllocator

相关推荐