问题 :

  • netty的 ByteBuff 和传统的ByteBuff的区别是什么?
  • HeapByteBuf 和 DirectByteBuf 的区别 ?
    HeapByteBuf : 使用堆内存,缺点 ,socket 传输的时候由于需要复制的原因,慢一点
    DirectByteBuf : 堆外内存,可以使用零拷贝

概述

netty ByteBuf 存在两个指针,分成三个区域: 已读区(可丢弃),未读区(未读),可写区 。不像之前JDK 的 ByteBuffer 中只有一个position 指针。例如以下示例 :
    public static void main(String[] args){
ByteBuffer buffer = ByteBuffer.allocate(88);
String value = "Netty~~";
buffer.put(value.getBytes());
//注意这个flip()方法,要是不调用,将读取到不正确的位置
buffer.flip();
byte[] vArray = new byte[buffer.remaining()];
buffer.get(vArray);
String result = new String(vArray);
System.out.println(result);
}
概述一下netty ByteBuff 的特点 :
  • 丰富API,存在readIndex 和 writeIndex 两个指针,方便读写
  • 动态扩容
  • 提供兼容 JDK ByteBuffer的方法

分类

内存池,循环利用创建的 ByteBuf 对象提升内存使用效率,降低由于高负载导致的频繁 GC .
PooledByteBuf 抽象类的子类 :
  • PooledDirectByteBuf
  • PooledHeapByteBuf
  • PooledUnsafeDirectByteBuf
    看一下类的结构图

源码分析

AbstractByteBuf 源码分析

    @Override
public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
checkReadableBytes(length);
//抽象方法交由子类实现
getBytes(readerIndex, dst, dstIndex, length);
readerIndex += length;
return this;
}
看一下写操作
    @Override
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
ensureWritable(length);
setBytes(writerIndex, src, srcIndex, length);
writerIndex += length;
return this;
} @Override
public ByteBuf ensureWritable(int minWritableBytes) {
if (minWritableBytes < 0) {
throw new IllegalArgumentException(String.format(
"minWritableBytes: %d (expected: >= 0)", minWritableBytes));
} if (minWritableBytes <= writableBytes()) {
return this;
} if (minWritableBytes > maxCapacity - writerIndex) {
throw new IndexOutOfBoundsException(String.format(
"writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",
writerIndex, minWritableBytes, maxCapacity, this));
} // Normalize the current capacity to the power of 2.
int newCapacity = calculateNewCapacity(writerIndex + minWritableBytes); // Adjust to the new capacity.
capacity(newCapacity);
return this;
} /**
* 计算新容量并没有一下子就增加一倍这样的简单思路,而是一点点地增加。
*
*/
private int calculateNewCapacity(int minNewCapacity) {
final int maxCapacity = this.maxCapacity;
final int threshold = 1048576 * 4; // 4 MiB page if (minNewCapacity == threshold) {
return threshold;
} // If over threshold, do not double but just increase by threshold.
if (minNewCapacity > threshold) {
int newCapacity = minNewCapacity / threshold * threshold;
if (newCapacity > maxCapacity - threshold) {
newCapacity = maxCapacity;
} else {
newCapacity += threshold;
}
return newCapacity;
} // Not over threshold. Double up to 4 MiB, starting from 64.
int newCapacity = 64;
while (newCapacity < minNewCapacity) {
newCapacity <<= 1;
} return Math.min(newCapacity, maxCapacity);
}
 丢弃已读区域,复用缓冲区
    @Override
public ByteBuf discardReadBytes() {
ensureAccessible();
if (readerIndex == 0) {
return this;
} if (readerIndex != writerIndex) {
//子类实现,字节数组进行复制,读写区域进行前移
setBytes(0, this, readerIndex, writerIndex - readerIndex);
writerIndex -= readerIndex;
adjustMarkers(readerIndex);
readerIndex = 0;
} else {
adjustMarkers(readerIndex);
writerIndex = readerIndex = 0;
}
return this;
} protected final void adjustMarkers(int decrement) {
int markedReaderIndex = this.markedReaderIndex;
if (markedReaderIndex <= decrement) {
this.markedReaderIndex = 0;
int markedWriterIndex = this.markedWriterIndex;
if (markedWriterIndex <= decrement) {
this.markedWriterIndex = 0;
} else {
this.markedWriterIndex = markedWriterIndex - decrement;
}
} else {
this.markedReaderIndex = markedReaderIndex - decrement;
markedWriterIndex -= decrement;
}
}

AbstractReferenceCountedByteBuf 源码分析

 从名字看出该类主要对引用进行计数,类似于JVM 内存回收的对象引用计数器,用于跟踪对象的分配和销毁,做自动内存回收。
public abstract class AbstractReferenceCountedByteBuf extends AbstractByteBuf {
//利用原子类进行CAS 操作,保证了线程安全
private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> refCntUpdater =
AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt"); private static final long REFCNT_FIELD_OFFSET; static {
long refCntFieldOffset = -1;
try {
if (PlatformDependent.hasUnsafe()) {
refCntFieldOffset = PlatformDependent.objectFieldOffset(
AbstractReferenceCountedByteBuf.class.getDeclaredField("refCnt"));
}
} catch (Throwable t) {
// Ignored
} REFCNT_FIELD_OFFSET = refCntFieldOffset;
} @SuppressWarnings("FieldMayBeFinal")
private volatile int refCnt = 1; @Override
public final boolean release() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt == 0) {
throw new IllegalReferenceCountException(0, -1);
} if (refCntUpdater.compareAndSet(this, refCnt, refCnt - 1)) {
if (refCnt == 1) {
deallocate();
return true;
}
return false;
}
}
} @Override
public ByteBuf retain() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt == 0) {
throw new IllegalReferenceCountException(0, 1);
}
if (refCnt == Integer.MAX_VALUE) {
throw new IllegalReferenceCountException(Integer.MAX_VALUE, 1);
}
//CAS 操作
if (refCntUpdater.compareAndSet(this, refCnt, refCnt + 1)) {
break;
}
}
return this;
} ....
这个类有三个重要的字段,一个原子类用于多线程操作,保证线程安全。REFCNT_FIELD_OFFSET 是一个内存偏移量,用于标识 refCnt字段在AbstractReferenceCountedByteBuf这个类
的内存地址,最后一个refCnt 是用 volatile 修饰的变量,保存对象应用次数。

UnpooledHeapByteBuf 非内存池堆内存ByteBuf源码分析

public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {

	//内存分配
private final ByteBufAllocator alloc;
//字节缓存区
private byte[] array;
//作用和 JDK ByteBuffer 的转化
private ByteBuffer tmpNioBuf; ... private int getBytes(int index, GatheringByteChannel out, int length, boolean internal) throws IOException {
ensureAccessible();
ByteBuffer tmpBuf;
//使用自身字段 tmpNioBuf 进行操作返回,所以 UnpooledHeapByteBuf 是在 JDK ByteBuff 的基础上进行扩展的。
if (internal) {
tmpBuf = internalNioBuffer();
} else {
tmpBuf = ByteBuffer.wrap(array);
}
return out.write((ByteBuffer) tmpBuf.clear().position(index).limit(index + length));
} @Override
public int readBytes(GatheringByteChannel out, int length) throws IOException {
checkReadableBytes(length);
int readBytes = getBytes(readerIndex, out, length, true);
readerIndex += readBytes;
return readBytes;
}

总结

文章主要介绍netty buffer 相关的知识,主要是父类方法和 unpooled 相关的实现。

参考资料

  • 《netty 权威指南》

netty(六) buffer 源码分析的更多相关文章

  1. 《深入探索Netty原理及源码分析》文集小结

    <深入探索Netty原理及源码分析>文集小结 https://www.jianshu.com/p/239a196152de

  2. Netty 核心组件 Pipeline 源码分析(二)一个请求的 pipeline 之旅

    目录大纲: 前言 针对 Netty 例子源码做了哪些修改? 看 pipeline 是如何将数据送到自定义 handler 的 看 pipeline 是如何将数据从自定义 handler 送出的 总结 ...

  3. Netty中FastThreadLocal源码分析

    Netty中使用FastThreadLocal替代JDK中的ThreadLocal[JAVA]ThreadLocal源码分析,其用法和ThreadLocal 一样,只不过从名字FastThreadLo ...

  4. 【Netty之旅四】你一定看得懂的Netty客户端启动源码分析!

    前言 前面小飞已经讲解了NIO和Netty服务端启动,这一讲是Client的启动过程. 源码系列的文章依旧还是遵循大白话+画图的风格来讲解,本文Netty源码及以后的文章版本都基于:4.1.22.Fi ...

  5. Netty 5.0源码分析-ByteBuf

    1. 概念 Java NIO API自带的缓冲区类功能相当有限,没有经过优化,使用JDK的ByteBuffer操作更复杂.故而Netty的作者Trustin Lee为了实现高效率的网络传输,重新造轮子 ...

  6. Netty 5.0源码分析之综述

    1. 前言 本系列主要是用于梳理Netty的架构流程,深入设计细节,重点关注Netty是如何实现它所声称的特性. (ps:本人水平有限,如有错误,请不吝指教 : )) 2. 什么是Netty Nett ...

  7. 基于Netty的RPC架构学习笔记(五):netty线程模型源码分析(二)

    文章目录 小技巧(如何看开源框架的源码) 源码解析 阅读源码技巧 打印查看 通过打断点调试 查看调用栈 小技巧(如何看开源框架的源码) 一断点 二打印 三看调用栈 四搜索 源码解析 //设置nioso ...

  8. netty之EventLoop源码分析

    我们在讲解服务端和客户端时经常会看到提交一个任务到channel对应的EventLoop上,后续的io事件监听和任务执行都在EventLoop完成,可以说EventLoop是netty最核心的组件,我 ...

  9. Netty Recycler的源码分析

    Recycler分析 调用来源:PooledByteBuf.java 涉及的知识: AtomicInteger WeakReference ThreadLocal 在DefaultHandle 中调用 ...

随机推荐

  1. ASP.NET Razor 语法

    主要的 Razor C# 语法规则 Razor 代码块包含在 @{ ... } 中 内联表达式(变量和函数)以 @ 开头 代码语句用分号结束 变量使用 var 关键字声明 字符串用引号括起来 C# 代 ...

  2. [NOI2014] 魔法森林 - Link Cut Tree

    [NOI2014] 魔法森林 Description 给定一张图,每条边 \(i\) 的权为 \((a_i,b_i)\), 求一条 \(1 \sim n\) 路径,最小化 \(\max_{i\in P ...

  3. 安装php-zbarcode的步骤方法

    1 安装ImageMagick依赖 yum install ImageMagick ImageMagick-devel 2 安装zbar拓展 wget -c http://jaist.dl.sourc ...

  4. yii2模型

    多对多可以使用all()来调用 对数据提供者进行修改 /** * Lists all ArticleCate models. * @return mixed */ public function ac ...

  5. AcWing 4. 多重背包问题

    朴素 数据范围小 //数据范围小 #include<iostream> #include<algorithm> using namespace std ; ; int n,m; ...

  6. Junit +cucumber 运行报错 initiallizationError

    step1: 访问 https://search.maven.org/  搜索下载相关jar包 step2: 访问 http://maven.outofmemory.cn/info.cukes/cuc ...

  7. anaconda+pytorch安装(无GPU版本)

    anaconda+pytorch安装(无GPU版本) 待办 https://blog.csdn.net/nnUyi/article/details/78471326

  8. 2.springboot------微服务

    什么是微服务? 微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成一系列小服务的组合:可以通过http的方式进行互通.要说微服务架构,先得说说过去我们的单体应用架构. 单体应用架 ...

  9. 2.17NOIP模拟赛(by hzwer) T1 小奇挖矿

    [题目背景] 小奇要开采一些矿物,它驾驶着一台带有钻头(初始能力值 w)的飞船,按既定 路线依次飞过喵星系的 n 个星球. [问题描述] 星球分为 2 类:资源型和维修型. 1. 资源型:含矿物质量 ...

  10. Codeforces Round #619 (Div. 2)C(构造,容斥)

    #define HAVE_STRUCT_TIMESPEC #include<bits/stdc++.h> using namespace std; int main(){ ios::syn ...