因为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 内存分配有几种方式同使用场景,直接内存如果不手动回收的话一定要注意引用否则会出现内存泄漏

[编织消息框架][netty源码分析]10 ByteBuf 与 ByteBuffer的更多相关文章

  1. [编织消息框架][netty源码分析]11 ByteBuf 实现类UnpooledHeapByteBuf职责与实现

    每种ByteBuf都有相应的分配器ByteBufAllocator,类似工厂模式.我们先学习UnpooledHeapByteBuf与其对应的分配器UnpooledByteBufAllocator 如何 ...

  2. [编织消息框架][netty源码分析]13 ByteBuf 实现类CompositeByteBuf职责与实现

    public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf ...

  3. [编织消息框架][netty源码分析]12 ByteBuf 实现类UnpooledDirectByteBuf职责与实现

    public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf { private final ByteBufAl ...

  4. [编织消息框架][netty源码分析]1分析切入点

    在分析源码之前有几个疑问 1.BOSS线程如何转交给handle(业务)线程2.职业链在那个阶段执行3.socket accept 后转给上层对象是谁4.netty控流算法 另外要了解netty的对象 ...

  5. [编织消息框架][netty源码分析]2 eventLoop

    eventLoop从命名上看是专门处理事件 事件系统主要由线程池同队列技术组成,有以下几个优点 1.任务出队有序执行,不会出现错乱,当然前提执行线程池只有一个 2.解偶系统复杂度,这是个经典的生产者/ ...

  6. [编织消息框架][netty源码分析]11 UnpooledHeapByteBuf 与 ByteBufAllocator

    每种ByteBuf都有相应的分配器ByteBufAllocator,类似工厂模式.我们先学习UnpooledHeapByteBuf与其对应的分配器UnpooledByteBufAllocator 如何 ...

  7. [编织消息框架][netty源码分析]6 ChannelPipeline 实现类DefaultChannelPipeline职责与实现

    ChannelPipeline 负责channel数据进出处理,如数据编解码等.采用拦截思想设计,经过A handler处理后接着交给next handler ChannelPipeline 并不是直 ...

  8. [编织消息框架][netty源码分析]4 eventLoop 实现类NioEventLoop职责与实现

    NioEventLoop 是jdk nio多路处理实现同修复jdk nio的bug 1.NioEventLoop继承SingleThreadEventLoop 重用单线程处理 2.NioEventLo ...

  9. [编织消息框架][netty源码分析]5 eventLoop 实现类NioEventLoopGroup职责与实现

    分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...

随机推荐

  1. 转:Linux中文显示乱码?如何设置centos显示中文

    怎么设置Linux系统中文语言,这是很多小伙伴在开始使用Linux的时候,都会遇到一个问题,就是终端输入命令回显的时候中文显示乱码.出现这个情况一般是由于没有安装中文语言包,或者设置的默认语言有问题导 ...

  2. windows 上优雅的安装 node 和 npm

    windows 的一键安装包,应该是最简单的 node 安装方式. 其实很多软件,拷贝过来就可以运行,根本不需要所谓的"安装"过程. 新建一个目录专门了管理 node 和 npm  ...

  3. 【JAVAWEB学习笔记】17_jsp

    动态页面技术(JSP/EL/JSTL) 学习目标 案例:完成商品的列表的展示 一.JSP技术 1.jsp脚本和注释 jsp脚本: 1)<%java代码%> ----- 内部的java代码翻 ...

  4. numpy之索引和切片

    索引和切片 一维数组 一维数组很简单,基本和列表一致. 它们的区别在于数组切片是原始数组视图(这就意味着,如果做任何修改,原始都会跟着更改). 这也意味着,如果不想更改原始数组,我们需要进行显式的复制 ...

  5. Python爬虫学习之获取网页源码

    偶然的机会,在知乎上看到一个有关爬虫的话题<利用爬虫技术能做到哪些很酷很有趣很有用的事情?>,因为强烈的好奇心和觉得会写爬虫是一件高大上的事情,所以就对爬虫产生了兴趣. 关于网络爬虫的定义 ...

  6. 第三方登录SDK

    紧接着上次的第三方登录文档,这一波又来了. 一.使用qq登录https://connect.qq.com/ 首次登录的话会跳转到应用开发者注册,自己测试的话选择个人.下面的各项自己按真实情况填写. 注 ...

  7. Java Primitives and Bits

    Integer when processors were 16 bit, an int was 2 bytes. Nowadays, it's most often 4 bytes on a 32 b ...

  8. 细说C#中的系列化与反系列化的基本原理和过程

    虽然我们平时都使用第三方库来进行系列化和反系列化,用起来也很方便,但至少得明白系列化与反系列化的基本原理. 注意:从.NET Framework 2.0 开始,系列化格式化器类SoapFormatte ...

  9. 2.solr学习速成之安装

    1.下载解压solr-5.3.1.tgz [root@205 opt]# tar -zxf solr-5.3.1.tgz -C /opt/module/ 2.将solr-5.3.1/server/so ...

  10. JMETER 不同线程组 变量值 的参数传递

    线程组 1   在线程组1中使用__setProperty函数设置jmeter属性值(此值为全局变量值),将所需变量值如${token}设置为jmeter属性值,即newtoken,示例: 1.添加- ...