Okio之SegmentPool

同样,先看类简介:

A collection of unused segments, necessary to avoid GC churn and zero-fill.
This pool is a thread-safe static singleton.

大概是:没被使用的Segment的一个收集器。必要滴避免了GC导致的内存抖动和零填充。这个SegmentPool是一个线程安全的静态单例。

常量

  /** SegmentPool所能容你的最大字节数 */
  // TODO: Is 64 KiB a good maximum size? Do we ever have that many idle segments?
  //注:64KB是不是一个比较好的内存限制呢?我也不知道。但是它相当于8个Segment的大小,一般来说是足够了。
  static final long MAX_SIZE = 64 * 1024; // 64 KiB.

  /** Singly-linked list of segments. */
  static Segment next;

  /** 当前池里(pool)所有的字节数 */
  static long byteCount;

从这些变量可以大概得出:SegmentPool大概就是一个单链表或队列等线性结构,也就是一个大概8个Segment组成的线性结构,节点就是Segment。

方法

  • recycle(Segment):void 回收Segment,以待复用
static void recycle(Segment segment) {
    //将要回收的Segment还在使用中,不能进行回收,报异常!
    if (segment.next != null || segment.prev != null) throw new IllegalArgumentException();
    // 这是个处于共享状态的Segment,不能进行回收
    if (segment.shared) return; 
    //加锁处理回收操作,避免多线程环境的干扰
    synchronized (SegmentPool.class) {
      //若是当前池内的字节数byteCount加上一个Segment的最大容量已经超出了pool的最大容量,
      //表示pool空间不足,那就不能就行回收
      if (byteCount + Segment.SIZE > MAX_SIZE) return; 
      //改变当前池内字节量
      byteCount += Segment.SIZE;
      //添加到头部,所以应该是单链表结构
      segment.next = next;
      //重置Segment的pos和limit变量值
      segment.pos = segment.limit = 0;
      next = segment;
    }
  }

重置过程如下:
1、调用之前的关系

Okio之SegmentPool_第1张图片
image.png

2、segment.next = next
Okio之SegmentPool_第2张图片
image.png

3、next = segment;
Okio之SegmentPool_第3张图片
image.png

此时,我更愿意把SegmentPool的实例对象当做整个链表的Head,相当于头指针,仅仅有一个方便插入Segment的作用。

  • take():Segment 获取Segment进行复用
static Segment take() {
    //加锁,同一时间内只能有一个对象发访问这段代码块
    synchronized (SegmentPool.class) {
      if (next != null) {
        Segment result = next;
        next = result.next;
        result.next = null;
        byteCount -= Segment.SIZE;
        return result;
      }
    }
    return new Segment(); 
  }

得到一个可以重用的Segment,若池内不存在可以复用的Segment,则直接new出来使用。若不为空,则取出聊飙升第一个Segment即可,当然,还得做断链、重新连接保持链式操作、重新计算池内容量大小等操作。



与Segment的数据结构不同,pool只是用了单链表结构。因为对于复用的segment来说,只要能在池内找到,定然可以复用,故而不需要额外的操作,使用单链表已经是很简单明了的了。至此,SegmentPool的分析大概结束。

你可能感兴趣的:(Okio之SegmentPool)