文档章节

Jetty源码-IO-BufferBufferPool

robin-yao
 robin-yao
发布于 2015/04/18 15:10
字数 1012
阅读 56
收藏 0
点赞 1
评论 0

   继续上文Jetty源码-IO-BufferUtil  ,接着讲解下Jetty ByteBufferPool的实现。

   主要介绍ArrayByteBufferPool的实现,大概的原理是用Bucket数据来放要池化的ByteBuffer。桶的结构包含了它要池化ByteBuffer容量的大小Size  和  一个Queue (这里采用的是ConcurrentLinkedQueue,线程安全)。一个ByteBufferPool包含了两个Bucket[],一个用来放direct类型的ByteBuffer,一个用来放Heap类型的ByteBuffer。ByteBufferPool初始化的时候会把两个桶的每个成员都初始化。一个Bucket盛放对应相应capacity大小的的ByteBuffer。比如 我们ByteBufferPool池化可以放置最大容量为1024*60 到最小容量为0的ByteBuffer。对应的Bucket数组初始化就是60个桶,从 1024大小的,2048大小的,3072大小的.....1024*60大小的桶,当我们需要ByteBuffer时,我们只需根据容量到相应的桶中的Queue取出来即可。

以下是具体代码

接口类:

public interface ByteBufferPool {

    /**
     * 获取指定大小的ByteBuffer.
     * @param size
     * @param direct  是否用direct内存
     * @return
     */
    public ByteBuffer acquire(int size,boolean direct);

    /**
     * 返还ByteBuffer,使之重用
     * @param buffer
     */
    public void release(ByteBuffer buffer);
    //ByteBufferPool的工具类,我们可以方便的用它来操作ByteBufferPool,当然不用也可以,大家可以先直接跳过
    //因为这个类有点会误导大家的思路。可以直接看ArrayByteBufferPool的实现就OK
    public static class Lease{
        private final ByteBufferPool byteBufferPool;
        private final List<ByteBuffer> buffers;
        private final List<Boolean>recycles;
        public Lease(ByteBufferPool byteBufferPool, List<ByteBuffer> buffers, List<Boolean> recycles) {
            this.byteBufferPool = byteBufferPool;
            this.buffers = buffers;
            this.recycles = recycles;
        }
        public ByteBuffer acquire(int capacity,boolean direct){
           ByteBuffer buffer=byteBufferPool.acquire(capacity,direct);
           BufferUtil.clearToFill(buffer);
           return  buffer;
        }
        //预先王ByteBuffer list中插入一个ByteBuffer
        public void prepend(ByteBuffer  buffer,boolean recycle){
            insert(0, buffer, recycle);
        }
        public void insert(int index, ByteBuffer buffer, boolean recycle) {
            buffers.add(index,buffer);
            recycles.add(index,recycle);
        }
        public void append(ByteBuffer buffer, boolean recycle) {
            buffers.add(buffer);
            recycles.add(recycle);
        }

        public List<ByteBuffer> getByteBuffers() {
            return buffers;
        }
        //buffer list 所有剩余长度
        public long getTotalLength() {
            long length = 0;
            for (int i = 0; i < buffers.size(); ++i)
                length += buffers.get(i).remaining();
            return length;
        }
        public int getSize() {
            return buffers.size();
        }
        //释放所有可以循环利用的ByteBuffer
        public void recycle() {
            for (int i = 0; i < buffers.size(); ++i)
            {
                ByteBuffer buffer = buffers.get(i);
                if (recycles.get(i))
                    byteBufferPool.release(buffer);
            }
            buffers.clear();
            recycles.clear();
        }
    }
}

具体的ArrayByteBufferPool的实现

public class ArrayByteBufferPool implements ByteBufferPool {
    private final int _min;
    private final Bucket[]_direct;
    private final Bucket[]_indirect;
    private final int _inc;
    public ArrayByteBufferPool()
    {
        this(0,1024,64*1024);
    }

    public ArrayByteBufferPool(int minSize, int increment, int maxSize) {
        //最小size不能大于增量
        if (minSize>=increment)
            throw new IllegalArgumentException("minSize >= increment");
        //最大size 必须是增量的整数倍,并且增量不能大于最大的size
        if ((maxSize%increment)!=0 || increment>=maxSize)
            throw new IllegalArgumentException("increment must be a divisor of maxSize");
        _min=minSize;
        _inc=increment;
        //初始化 maxSize/increment个桶,包含直接内存的与heap的
        _direct=new Bucket[maxSize/increment];
        _indirect=new Bucket[maxSize/increment];

        int size=0;
        for (int i=0;i<_direct.length;i++)
        {
            size+=_inc;
            _direct[i]=new Bucket(size);
            _indirect[i]=new Bucket(size);
        }
    }
    @Override
    public ByteBuffer acquire(int size, boolean direct) {
        //根据size找到对应size的桶
        Bucket bucket = bucketFor(size,direct);
        //如果queue中存在ByteBuffer,则直接返回
        ByteBuffer buffer = bucket==null?null:bucket._queue.poll();
        //初次使用 桶中的queue没有 ByteBuffer
        if (buffer == null){
            //(bucket==null)如果是由于size 超过pool的最大size,造成没有相应的桶
            int capacity = bucket==null?size:bucket._size;
            //分配相应size的ByteBuffer;
            buffer = direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity);
        }
        return buffer;
    }
    @Override
    public void release(ByteBuffer buffer) {
        if (buffer!=null){
            Bucket bucket = bucketFor(buffer.capacity(),buffer.isDirect());
            if (bucket!=null){
                BufferUtil.clear(buffer);
                //关键:这步是把相应size的ByteBuffer放到相应的size的桶中,byteBuffer入队,用来重用
                bucket._queue.offer(buffer);
            }
        }
    }
    //清空byteBuffer  pool
    public void clear(){
        for (int i=0;i<_direct.length;i++){
            _direct[i]._queue.clear();
            _indirect[i]._queue.clear();
        }
    }
    //根据size寻找 桶
    private Bucket bucketFor(int size,boolean direct) {
        if (size<=_min)
            return null;
        int b=(size-1)/_inc;
        if (b>=_direct.length)
            return null;
        Bucket bucket = direct?_direct[b]:_indirect[b];
        return bucket;
    }
    public static class Bucket{
        public final int _size;
        public final Queue<ByteBuffer> _queue= new ConcurrentLinkedQueue<>();
        Bucket(int size) {
            _size=size;
        }
        @Override
        public String toString()
        {
            return String.format("Bucket@%x{%d,%d}",hashCode(),_size,_queue.size());
        }
    }
}

简单的测试:

public class ByteBufferPoolTest {
    public static void main(String[]args){
        ByteBufferPool.Lease lease =
                new ByteBufferPool.Lease(new ArrayByteBufferPool(),
                                        new ArrayList<>(),
                                        new ArrayList<>());


        ByteBuffer buffer1=lease.acquire(100, false);
        lease.append(buffer1,true);
        buffer1.put("robin yao".getBytes());
        BufferUtil.flipToFlush(buffer1, 0);
        System.out.println(new String(buffer1.array()));
        lease.recycle();
        ByteBuffer buffer2=lease.acquire(100, false);
        //是否是同一个
        System.out.println(buffer1==buffer2);
    }
}

除了ArrayByteBufferPool的实现,还有MappedByteBufferPool的实现,利用ConcurrentMap实现,这里不做介绍

转发请标注来源:http://my.oschina.net/robinyao/blog/403334  

END-----------------------------------------

© 著作权归作者所有

共有 人打赏支持
robin-yao
粉丝 149
博文 54
码字总数 61496
作品 0
杭州
eclipse使用maven tomcat插件部署无法关联源代码

eclipse maven 起服务debug无法关联源码 博客分类: maven eclipse 1. 安装sourcelookup插件: update site: 1) http://bjmi.github.io/update-site/ (3.8.2可用,后续描述均针对此插件) 2) ht...

赵作文 ⋅ 2015/10/20 ⋅ 0

Jetty9 源码初解(2)——IO之EndPoint

一、概述 EndPoint作为jetty-io的一个重要组成部分,是基于javaNIO的封装,用于底层网络的读写,一旦网络读写准备好,会调用相应的connection的handle方法。 二、类分析 EndPoint源码如下: ...

戴的天 ⋅ 2015/10/28 ⋅ 0

Jetty源码-IO-BufferUtil

jetty 源码 BufferUtil 工具类主要是封装了对JDK ByteBuffer的操作。通过BufferUtil可以更容易的操作ByteBuffer. 由于ByteBuffer分为fill模式即写模式、flush模式即读模式,我们经常会在读写...

robin-yao ⋅ 2015/04/16 ⋅ 0

Spring Boot 2.0.0.M6 发布,初步支持 HTTP/2

Spring Boot 2.0.0.M6 已发布。该版本关闭了 144 个 issue 和 PR,继续向 2.0 GA 迈进。 该里程碑版改进了之前版本中的一些项目,也新增了一些特性,具体如下: 初步支持 HTTP/2:目前在 To...

淡漠悠然 ⋅ 2017/11/06 ⋅ 23

Jetty源码学习3-启动服务器

引言 本文主要介绍下环境准备、启动加载的配置文件的涵义和start.jar的加载原理。 环境准备 1、下载jetty-distribution-8.1.7.v20120910源码包并加入eclipse工程classpath中 2、准备一个war...

项籍20130121 ⋅ 2013/02/26 ⋅ 2

从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一)

从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一) 收藏 如何正确使用NIO来构架网络服务器一直是最近思考的一个问题,于是乎分析了一下Jetty、Tomcat和Mina有关NIO的源码,发现...

光石头 ⋅ 2011/02/20 ⋅ 0

jfinal 使用jetty启动报错 java.io.EOFException

之前都没有问题,就是前几天突然出现的,很奇怪,网上搜也没有相应的错误,望大神们指导指导 [WARN]-[Thread: main]-[org.eclipse.jetty.server.session.HashSessionManager.restoreSession(...

walala_Lee ⋅ 2013/04/23 ⋅ 2

JFinal 序列号的问题,发生冲突

下午在修改User类方法的时候,突然就出现了这个问题,之前一直都没问题。一直找不到哪里出了问题,后来把类名换成UserABC,结果又报java.lang.ClassNotFoundException: com.demo.user.User 急...

Knight_King ⋅ 2013/05/10 ⋅ 1

从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一)

如何正确使用NIO来构架网络服务器一直是最近思考的一个问题,于是乎分析了一下Jetty、Tomcat和Mina有关NIO的源码,发现大伙都基于类似的方式,我感觉这应该算是NIO构架网络服务器的经典模式,...

山哥 ⋅ 2012/03/19 ⋅ 0

使用ActiveMQ传输文件出现early EOF错误

WARN | Exception occured org.eclipse.jetty.io.EofException: early EOF at org.eclipse.jetty.server.HttpInput.read(HttpInput.java:65) at java.io.InputStream.read(InputStream.java:......

深蓝浅爱 ⋅ 2016/11/21 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

volatile和synchronized的区别

volatile和synchronized的区别 在讲这个之前需要先了解下JMM(Java memory Model :java内存模型):并发过程中如何处理可见性、原子性、有序性的问题--建立JMM模型 详情请看:https://baike.b...

MarinJ_Shao ⋅ 34分钟前 ⋅ 0

深入分析Kubernetes Critical Pod(一)

Author: xidianwangtao@gmail.com 摘要:大家在部署Kubernetes集群AddOn组件的时候,经常会看到Annotation scheduler.alpha.kubernetes.io/critical-pod"="",以表示这是一个关键服务,那你知...

WaltonWang ⋅ 42分钟前 ⋅ 0

原子性 - synchronized关键词

原子性概念 原子性提供了程序的互斥操作,同一时刻只能有一个线程能对某块代码进行操作。 原子性的实现方式 在jdk中,原子性的实现方式主要分为: synchronized:关键词,它依赖于JVM,保证了同...

dotleo ⋅ 48分钟前 ⋅ 0

【2018.06.22学习笔记】【linux高级知识 14.4-15.3】

14.4 exportfs命令 14.5 NFS客户端问题 15.1 FTP介绍 15.2/15.3 使用vsftpd搭建ftp

lgsxp ⋅ 58分钟前 ⋅ 0

JeeSite 4.0 功能权限管理基础(Shiro)

Shiro是Apache的一个开源框架,是一个权限管理的框架,实现用户认证、用户授权等。 只要有用户参与一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户...

ThinkGem ⋅ 昨天 ⋅ 0

python f-string 字符串格式化

主要内容 从Python 3.6开始,f-string是格式化字符串的一种很好的新方法。与其他格式化方式相比,它们不仅更易读,更简洁,不易出错,而且速度更快! 在本文的最后,您将了解如何以及为什么今...

阿豪boy ⋅ 昨天 ⋅ 0

Python实现自动登录站点

如果我们想要实现自动登录,那么我们就需要能够驱动浏览器(比如谷歌浏览器)来实现操作,ChromeDriver 刚好能够帮助我们这一点(非谷歌浏览器的驱动有所不同)。 一、确认软件版本 首先我们...

blackfoxya ⋅ 昨天 ⋅ 0

线性回归原理和实现基本认识

一:介绍 定义:线性回归在假设特证满足线性关系,根据给定的训练数据训练一个模型,并用此模型进行预测。为了了解这个定义,我们先举个简单的例子;我们假设一个线性方程 Y=2x+1, x变量为商...

wangxuwei ⋅ 昨天 ⋅ 0

容器之查看minikue的environment——minikube的环境信息

执行如下命令 mjduan@mjduandeMacBook-Pro:~/Docker % minikube docker-envexport DOCKER_TLS_VERIFY="1"export DOCKER_HOST="tcp://192.168.99.100:2376"export DOCKER_CERT_PATH="/U......

汉斯-冯-拉特 ⋅ 昨天 ⋅ 0

mysql远程连接不上

设置了root所有hosts远程登录,可是远程登录还是失败,原因可能如下: 登录本地数据库 mysql -uroot -p123456 查询用户表 mysql> select user,host,password from mysql.user; 删除密码为空的...

冰公子 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部