同样,先看类简介:
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、调用之前的关系
2、segment.next = next
3、next = segment;
此时,我更愿意把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的分析大概结束。