1.性能层面基础的单位影响
2.android对于IO需要注意的场景
3.IO的优化是在解决CPU的瓶颈问题,但是通常在C端很少会出现,所以在学习IO的角度上来说,我们不会把重点放在CPU瓶颈的解决,而是会探寻IO本质原理及序列化的应用与Dex文件的加壳脱壳
4.内核空间
5.内核(Linux)的IO栈
我们可以把Linux存储系统的IO栈,由上到下分为三个层次,,分别是文件系统层,通用块层和设备层
文件系统层,包括了虚拟文件系统和其他各种文件系统的具体实现,它为上层的应用程序提供标准的文件访问接口,对下会通过块层,来存储和管理磁盘数据
通用块层,包括块设备io队列和io调度器,它会对文件系统的io请求进行排队,再通过重新排序和请求合并,然后才发送给下一级的设备层。
设备层,包括存储设备和相应的驱动程序,负责最终物理设备的io操作
存储系统的io,通常是整个系统中最慢的一环,所以,Linux通过多种缓存机制来优化io效率
为了优化存储系统访问文件的性能,会使用页缓存,索引节点缓存,目录项缓存等多种缓存机制,以及减少对下层块设备的直接调用
为了优化块设备的访问效率,会使用缓冲区,来缓存块设备的数据
6.页
4k数据为一页,一页数据是IO操作的基本单位
7.空间局部性原理
在常规操作下,如果数据量较大的情况下可能会出现预占位4-16k的情况
8.系统在进行IO操作的时候,会有一组优化方案存在,在每次操作的数据为4k1页,但是为了优化可能扩展到8k,在分配到具体物理内存的时候,我给你8k数据,就占用8k数据,但是我看着你还不断的写,我提前先给你8k或者16k,下次,看你空间够用了,不分配,接着用,不够了再分配
9.刚才验证了缓冲区,java的缓冲方案是自己缓冲区搞8k大小,每次数据到达8k进行一次同步调用,一次性4k是内核的操作方案,是操作系统的操作方案,底层是以1页去操作的,用buffer.flush()可以手动调用一次同步,memIO()这个函数模拟IO操作,在栈中自己创建了一个数组在玩,实际上根本没有触发IO操作
10.基础流意味着复制调用频繁
11.断点续传,断点下载,做数据分析,大数据里面应用,也可以做并行计算
12.IO的底层原理
实际上是调用内核的函数库,进行数据同步之后,然后由内核将数据写入到磁盘
13.缓存区概念
因为基础IO的相关处理方案,每一次写入都会直接调用复制,在当前自己程序,将数据缓存起来,然后达到8k一次性写出
14.java对于IO提供了N种方案的支撑
RandomAccessFile()功能上讲提供定位处理
缓冲区上讲,提供了MapperByteBuffer,这个是内核与APP缓冲共享
MapperByteBuffer是NIO提供的
非阻塞IO,应用层面上来讲,JDK提供了一套非阻塞实现方案所推出的相关API,对于调用(IO相关函数)的实现是JAVA做的
basicIO基于阻塞模型去做
IO模型概念:实现IO的具体方案,Java这边的调用过程
IO分两个阶段去做:
1.数据准备阶段
2.内核空间复制回用户进程缓冲区阶段(调用内核函数,完成相关复制)
具体的IO实际操作是由内核完成的,我们是提供数据的人
内核那边提供的那几个函数,由下面这种搞法:
阻塞IO:我们这边数据没准备好,那么内核那边阻塞住等待数据过来,过来之后继续执行下面的操作
缺点:如果在高强度并发的情况下,很容易将CPU拉满,内存处理需要有线程,实际上就是和内核建立联系,CPU的损耗会比较大,10000QBS(一秒10000次连接)进来后CPU扛不住
缺页,中断
传统的阻塞IO
非阻塞IO
轮询的时候,其他业务正常跑,不会卡住
非阻塞IO对于阻塞IO的提升:可以接受更多的任务,任务量可以增多
IO的复用模型
五个IO模型的对比
1.内核系统提供了N多个函数
2.recv/fsync/sync/poll/select
3.这些函数有相关功能,java通过这些函数不同的功能,组合开发了五套IO的具体实现方案
4.recvform
OKIO
okhttp
okhttp团队自己对于IO这一块写了一套,底层还是java的basic实现,但是基于网络这一块的频繁IO访问,他认为当前的IO性能上有瓶颈,这个瓶颈出现在网络通信调用一般是双向的,涉及到一次InputStream和一次OutputStream,就会涉及到一次读的IO复制和一次写的IO复制,如果做缓存的话,就会搞出两个byte去支撑
**优化:**做一个
Segment数组双向链表
ok里面source是读,sink代表是写
OKIO采取的方案
OKIO核心竞争力为,增强了流与流之间的互动,使得当数据从一个缓冲区移动到另一个缓冲区时,可以不经过copy能到达:
1.以Segment作为存储结构,真实数据以类型为byte[]的成员变量data存在,并用其它变量标记数据状态,在需要时,如果可以,移动Segment引用,而非copy data数据
2.Segment在Segment线程池中以单链表存在以便复用,在buffer中以双向链表存在存储数据,head指向头部,是最老的数据。
3.Segment能通过slipt()进行分割,可实现数据共享,能通过compact()进行合并,由buffer来进行数据调度,基本遵守“大块数据移动引用,小块数据进行copy”的思想
4.source对应输入流,sink对应输出流
5.TimeOut以达到在期望时间内完成IO操作的目的,同步超过在每次IO操作中检查消耗,一部超时开启另一个线程间隔时间检查耗时。
6.OK核心是解决双流操作问题
总结:
IO原理,本质基于内核提供的函数,功能由内核完成,java所提供的IO是依托于内核函数的一个实现(注磁盘和网卡也是IO设备)