• 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设备)

  • 相关阅读:
    微信小程序 onTabItemTap点击底部导航栏
    回归预测 | MATLAB实现BP神经网络多输入单输出回归预测
    面经——C++语言1
    JAVA 枚举的基础、应用和原理
    【Linux】Nignx的入门&使用负载均衡&动静分离(前后端项目部署)---超详细
    使用Docker构建轻量级Linux容器
    sizeof函数的用法
    PHP 简介
    从油猴脚本管理器的角度审视Chrome扩展
    【Linux】文件系统
  • 原文地址:https://blog.csdn.net/weixin_43580319/article/details/126585432