Android I/O 那些事儿

I/O 操作是编程离不开的话题,它不仅是读写那么简单,还涉及底层的文件系统和存储设备。I/O 的快慢影响程序的执行效率,这篇文章主要介绍 Android 平台 I/O 的方式和使用场景。

1. Linux I/O 的基本组成

众所周知,Android 基于 Linux 系统,先介绍一些 Linux 上 I/O 的知识。

I/O 操作由应用程序、文件系统和磁盘共同完成,应用程序将 I/O 命令发送给文件系统,文件系统在合适的时间把 I/O 指令发送给磁盘。I/O 的流程如下图:

I/O操作

CPU 和内存的速度比磁盘快得多,I/O 操作的瓶颈在于磁盘的性能。为了降低磁盘对应用程序的影响,文件系统要进行各种各样的优化。

文件系统

简单来说,文件系统就是存储和组织数据的方式。应用程序调用 read() 方法,系统会通过中断从用户空间进入内核空间,然后经过虚拟文件系统、具体文件系统、页缓存。

Linux-I/O架构
  • 虚拟文件系统(VFS)。主要用于屏蔽具体的文件系统,为应用程序的操作提供一个统一的接口。
  • 文件系统(File System)。ext4、F2FS 都是具体文件系统实现。每个文件系统都有适合自己的场景。
  • 页缓存(Page Cache)。文件系统对数据的缓存,读文件时先检查页缓存,如果命中就不去读磁盘。

磁盘

磁盘指的是系统的存储设备,常见的有机械硬盘、固态硬盘等。如果发现应用程序要读的数据没有在页缓存中,这时候就需要真正向磁盘发起 I/O 请求。磁盘 I/O 的过程要先经过内核的通用块层、I/O 调度层、设备驱动层,最后才会交给具体的硬件设备处理。

磁盘架构
  • 通用块层。接收上层发出的磁盘请求,并最终发出 I/O 请求。它与 VPS 的作用类似。
  • I/O 调度层。根据设置的调度算法对请求合并和排序。不能接收到磁盘请求就立刻交给驱动层处理。
  • 块设备驱动层。根据具体的物理设备,选择对应的驱动程序,通过操控硬件设备完成最终的 I/O 请求。

2. Android 上的 I/O

Android 现在普遍使用的是 Linux 常用的 ext4 文件系统。F2FS(Flash-Friendly File System)是三星为闪存研发的文件系统,它针对闪存进行了大量优化,F2FS 文件系统在小文件的随机读写方面比 ext4 更快。随着 Google、华为的投入和使用,F2FS 应该会成为 Android 主流的文件系统。

Android 手机使用闪存作为存储设备,也就是我们常说的 ROM。前几年闪存通常使用 eMMC 标准,近年来采用性能更好的 UFS 2.0/2.1 标准。手机存储也朝着体积更小、功耗更低、速度更快、容量更大的方向发展,闪存的随机读写速度甚至比 SSD 还快。

手机变卡

Android 手机用久了会变卡,除了系统升级、设备折旧等因素,还和 I/O 有密切关系。I/O 操作变慢的原因有下面几条:

  • 内存不足。系统回收 Page Cache 和 Buffer Cache 的内存,大部分的写操作会直接落盘,导致性能低下。
  • 写入放大。闪存重复写入需要先进行擦除,一次写入会引起整个块数据的迁移,导致写入时间非常久。
  • 设备性能差。在高负载的情况下容易出现瓶颈。

文件损坏

文件损坏是令人头疼的问题,大多是由不正确的操作导致的。文件损坏的原因可以从应用程序、文件系统和磁盘三个角度来分析:

  • 应用程序。大部分的 I/O 方法都不是原子操作,文件的跨进程或者多线程写入、使用一个已经关闭的文件描述符 fd 来操作文件,都有可能导致数据被覆盖或者删除。
  • 文件系统。虽说内核崩溃或者系统突然断电都有可能导致文件系统损坏,不过文件系统也做了很多的保护措施。例如 system 分区保证只读不可写,增加异常检查和恢复机制。
  • 磁盘。手机上使用的闪存是电子式的存储设备,所以在资料传输过程可能会发生电子遗失等现象导致数据错误。

3. I/O 的三种方式

I/O 有三种方式:标准 I/O、mmap 和 Direct I/O。

I/O的方式

标准 I/O

应用程序平时用到 read/write 操作都属于标准 I/O,也就是缓存 I/O(Buffered I/O)。它的关键特性有:

  • 对于读操作,当应用程序读取某块数据时,如果这块数据已经在页缓存中,那么就不需要经过物理读盘操作。
  • 对于写操作,应用程序会先将数据写到页缓存中去,不需要等全部数据被写回磁盘,系统会定期将页缓存中的数据刷到磁盘上。

缓存 I/O 可以很大程度减少真正读写磁盘的次数,从而提升性能。但是延迟写机制可能会导致数据丢失。在实际应用中,如果某些数据非常重要,我们应该采用同步写机制。

读操作时,数据会先从磁盘拷贝到 Page Cache 中,然后再从 Page Cache 拷贝到应用程序的用户空间,这样就会多一次内存拷贝。内存相对磁盘是高速设备,即使多拷贝一次,也比真正读一次硬盘要快。

mmap

mmap 把文件映射到进程的地址空间,提高了 I/O 的性能。

mmap 的优点有:

  • 减少系统调用。只需要一次 mmap() 系统调用,后续所有的调用像操作内存一样。
  • 减少数据拷贝。mmap 只需要从磁盘拷贝一次,由于做过内存映射,不需要再拷贝回用户空间。
  • 可靠性高。mmap 把数据写入页缓存后,跟缓存 I/O 的延迟写机制一样。

存在的缺点:

  • 虚拟内存增大。Apk、Dex、so 都是通过 mmap 读取。mmap 会导致虚拟内存增大,mmap 大文件容易出现 OOM。
  • 磁盘延迟。mmap 通过缺页中断向磁盘发起真正的磁盘 I/O,不能通过 mmap 消除磁盘 I/O 的延迟。

在 Android 中可以将文件通过 MemoryFile 或者 MappedByteBuffer 映射到内存,然后进行读写,使用这种方式对于小文件和频繁读写操作的文件还是有一定优势的。

mmap 比较适合对同一块区域频繁读写的情况,推荐使用 I/O 线程来操作。用户日志、数据上报都满足这种场景,另外需要跨进程同步的时候,mmap 也是一个不错的选择。Android 跨进程通信有自己独有的 Binder 机制,它内部也是使用 mmap 实现。

Direct I/O

一些数据库自己实现了数据和索引的缓存管理,对页缓存的依赖没那么强烈。它们想绕开页缓存机制,减少一次数据拷贝,它的数据也不会污染页缓存。

直接 I/O 访问文件方式减少了一次数据拷贝和一些系统调用的耗时,很大程度降低了 CPU 的使用率以及内存的占用。负面影响就是读写操作都是同步执行,导致应用程序等待。

4. 同步与异步 I/O

多线程阻塞式在 I/O 操作上的并没有优势,I/O 操作的主要瓶颈在于磁盘带宽。所以 I/O 操作不能开大量的线程。

NIO 是非阻塞 I/O,将 I/O 以事件的方式通知,可以减少线程切换的开销。NIO 的最大作用不是减少读取文件的耗时,而是最大化提升应用整体的 CPU 利用率。

另外,非常推荐 Square 的 Okio,它支持同步和异步 I/O,也做了比较多的优化。

I/O 优化对提升应用的体验非常有用,希望上面所讲的内容对你有帮助。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 今天看到一位朋友写的mysql笔记总结,觉得写的很详细很用心,这里转载一下,供大家参考下,也希望大家能关注他原文地...
    信仰与初衷阅读 4,725评论 0 30
  • feisky云计算、虚拟化与Linux技术笔记posts - 1014, comments - 298, trac...
    不排版阅读 3,815评论 0 5
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,182评论 0 9
  • 从这一章开始,我们探讨的话题就会与前面的话题稍有不同——我们将开始探讨操作系统对于设备的管理以及它为用户程序提供服...
    夏威夷的芒果阅读 1,379评论 0 0
  • 前言:在之前的面试中,每每问到关于Java I/O 方面的东西都感觉自己吃了大亏..所以这里抢救一下..来深入的了...
    我没有三颗心脏阅读 2,483评论 0 21