Android-从Basic IO到NIO内核机制(原理篇)

Posted 天津 唐秙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android-从Basic IO到NIO内核机制(原理篇)相关的知识,希望对你有一定的参考价值。

文章目录

从Basic IO到NIO内核机制

1. IO

1.性能层面基础的单位影响

  • 使用率:是指磁盘处理IO的时间百分比,过高的使用率(比如超过80%),通常意味着磁盘IO存在性能瓶颈
  • 饱和度:是指磁盘处理IO的繁忙程度,过高的饱和度,意味着磁盘存在着严重的性能瓶颈,当饱和度为100%时,磁盘无法接受新的
  • IOPS:是指每秒的IO请求大小,适用于大文件的情景
  • 吞吐量:是指每秒的IO请求大小,适用于大文件的情景
  • 响应时间:是指IO请求从发出到收到响应的时间间隔

2.android对于IO需要注意的场景

  • 设备(手机)作为S端
  • IO复用可能导致的空指针
  • 设备数据的传递
  • dex加壳和脱壳
  • NET IO
  • BASIC 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提供的

2. 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设备)

以上是关于Android-从Basic IO到NIO内核机制(原理篇)的主要内容,如果未能解决你的问题,请参考以下文章

NIO零拷贝的深入分析

BIO,NIO,AIO

阻塞、非阻塞、多路复用、同步、异步、BIO、NIO、AIO 一文搞定

7. NIO与零拷贝

Java NIO(New IO)

Java nio 空轮询bug到底是什么