Okio框架分析--之二
2017-09-20 20:53
162 查看
4.2 SegmentPool
SegmentPool就是片段池,可以说是管理Segment。三个变量如下,static final long MAX_SIZE = 64 * 1024; // 64 KiB.
static Segment next;
static long byteCount;
MAX_SIZE表示片段池的最大容量,表示片端池中最多可以容纳8个片段,next将片段连接成单向链表;
byteCount表示片端池当前包含的总字节数。
take方法如下,
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(); // Pool is empty. Don't zero-fill while holding a lock.
}
take方法用于从片段池中取片段,当next为空即片段池为空时,新建一个片段返回(此新建片段在用完后回收进片段池),
若片段池不为空则返回池中第一个片段,并将这个片段从片段池中移除,其中加锁防止多线程同时取数据。
recycle方法如下,
static void recycle(Segment segment) { if (segment.next != null || segment.prev != null) throw new IllegalArgumentException(); if (segment.shared) return; // This segment cannot be recycled. synchronized (SegmentPool.class) { if (byteCount + Segment.SIZE > MAX_SIZE) return; // Pool is full. byteCount += Segment.SIZE; segment.next = next; segment.pos = segment.limit = 0; next = segment; } }
recycle方法用于将不用的Segment回收至片段池,且首先要判断即将回收的Segment的next和prev是否已经置空,
即是否已经从Segment双向链表中正确的移除,然后还要判断此Segment是否为共享状态,为共享状态表示此Segment
可能还要执行一些操作,比如正在移动Segment,此时也不能进行回收,最后一层判断片段池能否容纳此Segment。
符合以上三个条件后进行回收,将此Segment参数初始化,加入单向链表,等待被取出使用。
4.3 write
下面通过Buffer的write方法分析Buffer是如何通过Segment和SegmentPool实现高效性的Buffer有一个write方法如下,
public void write(Buffer source, long byteCount) { if (source == null) throw new IllegalArgumentException("source == null"); if (source == this) throw new IllegalArgumentException("source == this"); checkOffsetAndCount(source.size, 0, byteCount); //判断参数的合理性 while (byteCount > 0) { // Is a prefix of the source's head segment all that we need to move? // 判断要移动的数据是否全部存储在source的第一个片段中 if (byteCount < (source.head.limit - source.head.pos)) { Segment tail = head != null ? head.prev : null; if (tail != null && tail.owner && (byteCount + tail.limit - (tail.shared ? 0 : tail.pos) <= Segment.SIZE)) { // Our existing segments are sufficient. Move bytes from source's head to our tail. //若目标片段tail可用且容量足以存储数据 // 将source头片段中的数据移动到目标片段tail source.head.writeTo(tail, (int) byteCount); source.size -= byteCount; size += byteCount; return; } else { // We're going to need another segment. Split the source's head // segment in two, then move the first of those two to this buffer. //若目标片段tail不可用或容量不足以存储数据 //使用split方法分割source片段,并将分割得到的待写入数据片段作为source的第一个片段 source.head = source.head.split((int) byteCount); } } // Remove the source's head segment and append it to our tail. // 将source第一个片段移动到目标片段 Segment segmentToMove = source.head; //移除source第一个片段,并将source的后置节点前移作为source第一个片段,相当于堆栈的出栈 long movedByteCount = segmentToMove.limit - segmentToMove.pos; source.head = segmentToMove.pop(); if (head == null) { //若待写入Buffer(即this)中没有任何片段,则直接将头片段指向数据片段 head = segmentToMove; head.next = head.prev = head; } else { //否则将数据片段移动到头片段的前置片段,并尝试压缩 Segment tail = head.prev; tail = tail.push(segmentToMove); tail.compact(); } //重置容量,若没有移动完则循环 source.size -= movedByteCount; size += movedByteCount; byteCount -= movedByteCount; } }
相关文章推荐
- 原理分析之二:框架整体设计
- 深入浅出 - Android系统移植与平台开发(十二) - Sensor HAL框架分析之二
- 原理分析之二:框架整体设计
- 原理分析之二:框架整体设计
- 原理分析之二:框架整体设计
- Mybatis原理分析之二:框架整体设计
- [置顶] Cocos2d-x 实例源码分析之二 小实例的主框架
- Android学习指南之二:分析Android框架及Android程序的目录结构
- Sensor HAL框架分析之二
- 深入浅出 - Android系统移植与平台开发(十二) - Sensor HAL框架分析之二
- 深入浅出 - Android系统移植与平台开发(十二) - Sensor HAL框架分析之二
- Okio框架分析--之一
- 原理分析之二:框架整体设计
- 原理分析之二:框架整体设计
- 深入浅出 - Android系统移植与平台开发(十二) - Sensor HAL框架分析之二
- 原理分析之二:框架整体设计
- Sensor HAL框架分析之二
- 深入浅出 - Android系统移植与平台开发(十二) - Sensor HAL框架分析之二
- 【mybatis源码分析】原理分析之二:框架整体设计
- 原理分析之二:框架整体设计