Okio源码解析之Sink

首先说明一点,本文属于概叙文,需要各位耐心阅读源码后来看这里的总结,一定会有所收获。
ps:Okio的源码真的挺少的。
再ps:阅读此博客,需要阅读Sink、BufferedSink,DeflaterSink和GzipSink,Buffer源码。

一、Sink整体关系图

Sink关系图

说明:
1、Sink是顶层接口,BufferedSink,DeflaterSink和GzipSink都是它的继承者

2、BufferedSink是接口,拓展了Sink的功能,多了一个Buffer类用于缓存

3、DeflaterSink是一个类,内部含有一个BufferedSink和Deflater,BufferedSink用于缓存,Deflater用于压缩。

4、ZipSink是一个类,内部含有一个BufferedSink,DeflaterSink和Deflater实例,其中BufferedSink用于缓存,DeflaterSink用于压缩,而Deflater用于实际压缩。
需要说明的是,在ZipSink中的BufferedSink和DeflaterSink中的Buffer都是同一个,而DeflaterSink中的Deflater和ZipSink中的Deflater也是同一个。

二、亮点

1、装饰者模式

Sink为每个继承类必须实现的功能,而继承类DeflaterSink中包含了一个BufferedSink实例,使得它装饰了Buffer功能,然后,DeflaterSink内部还有一个Deflater的实例,因此赋予它压缩的功能。

ZipSink则在内部包括了DeflaterSink和BufferedSink以及Deflater,但是前面也说过,DeflaterSink和BufferedSink中的Buffer是同一个,而Deflater和DeflaterSink中的Deflater也是同一个。

那么为什么不直接包含一个DeflaterSink就行了呢?我猜原因是因为容易操作。因为ZipSink装饰了DeflaterSink的压缩功能,并且在此基础上对buffer的头部和尾部加上压缩的标志,如果通过DeflaterSink去访问BufferedSink中的Buffer,就显得十分麻烦了。

同理,ZipSink关闭的时候,之所以有调用DeflaterSink的finishDeflate()函数去关闭Deflater,是因为在这个函数的内部还会对剩余的数据进行压缩,然后再关闭,之后ZipSink再调用Deflater的end()函数,使得整个流完全地安全关闭。

二、Buffer中Segment的使用

Buffer类

A collection of bytes in memory.

<p><strong>Moving data from one buffer to another is fast.</strong> 
Instead of copying bytes from one place in memory to another, this 
class just changes ownership of the underlying byte arrays.
<p><strong>This buffer grows with your data.</strong> 
Just like ArrayList,each buffer starts small. 
It consumes only the memory it needs to.
<p><strong>This buffer pools its byte arrays.</strong> 
When you allocate a byte array in Java, the runtime must zero-fill 
the requested array before returning it to you. Even if you're going
to write over that space anyway.This class avoids zero-fill and GC
churn by pooling byte arrays.

内存中字节的集合。

  • 从一个buffer转移数据到另一个buffer是高效的。
    在转移数据的时候不是将bytes从内存中的一块地方转移到另一块地方,
    而是仅仅改变byte arrays之间的关系。

  • 这个buffer随着数据的增大而自动拓展。
    像ArrayList一样,一开始每个buffer都很小。只占有必要的内存空间。

  • 将byte array与他人共享。
    在java中当分配一个byte array时,运行时系统会在将这个byte array给你前用0填充整个
    空间。Buffer类能够通过分享机制,避免了零填充问题和GC churn问题。

  • 同时实现了BufferedSource接口和BufferedSink接口

亮点:

一、Segment的使用:

Buffer类持有一个Segment head。而Segment是一个循环链表,内部封装着byte[]数组。

Segment中有一些规则:

  • 如果Segment的byte[]是从别的Segment中拷贝来的,则owner属性为false,
    Segment中的byte[]只能读不能写。

  • 在对Segment进行split的时候,如果要分割的字节数少,则采用直接copy的方法,
    只有在要分割的字节数大于一定的值,才会将Segment的byte[]共享给分割的Segment。
    做出这种选择的原因是:

    • 如果在分割的字节数少的情况下将Segment的byte[]分享出去,那么一个byte[]
      可能被许许多多个小的segment共享,这对性能会造成损耗。
    • 在字节数大的情况下如果采用copy的方式则会消耗内存。
  • Segment的byte[]会标记pos和limit,其中pos表示开始读取的位置,limit表示
    能够开始写的位置。一个byte[]被Segment进行切割,从而达到高效地使用。但是注
    易,如果一个Segment的owner==false,那么它只能读不能写,比如这里split时的
    prefix的Segment,如果是直接与原来的Segment共享,则它只能读不能写。

二、SegmentPool用于缓存Segment:

SegmentPool的规则:

  • 使用Segment next变量来指向下一个取出的Segment。

  • 规定SegmentPool的最大容量为64KB-

  • 往SegmentPool中take的时候,如果next不为null,则取出next,并且修改next
    的指针;否则的话则直接new一个Segment。(注意,取出来的Segment必须是独立的,也就是说
    Segment.next = null)

  • 往SegmentPool中take和recycle的时候都需要加锁

  • 往SegmentPool中添加Segment的时候,要满足以下条件:

    • segment必须是独立的,也就是segment.next == null && segment.prev == null.
    • segment必须是不与其他segment共享的,也就是shared == false
    • segment的容量必须小于等于SegmentPool最大剩余容量
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值