Android存储系统如何优化?

Posted 潘振杰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android存储系统如何优化?相关的知识,希望对你有一定的参考价值。

android存储系统如何优化?
答案是我也不知道…

那为什么会想到要写这篇文章哪?主要是因为有天晚上和以前一个同事讨论到Android手机存储系统的优化问题,我想把我知道的写下来。用过Android手机的人可能都会有这么个感觉,就是手机用久了之后系统会越来越慢。慢,其中很重要的一点就是和Android的存储系统有关。我们现在主流手机的内置存储芯片一般都是EMMC,一些旗舰级的Android手机已经在使用UFS接口的存储芯片,而iphone 6S开始更是用上了NVME接口的存储芯片。同事是做linux kernel相关工作的,他在想,是不是可以在kernel层面优化下Android的存储系统,改善下EMMC的坏块管理、磨损均衡等内容。

接触过一年的SSD固件开发,没有接触过EMMC。但是根据我的理解,EMMC其实就是一个弱化版或者叫精简版的SSD,核心原理和思想是一样的。所以我得出的答案是:同事想做的那些事,kernel什么也做不了。首先来一张大图,我们可以看到,磨损均衡、垃圾回收、坏块管理,这些事情已经全部被SSD、EMMC做掉了,主机端在这些事情上可以说是完全透明的。同事的想法其实还停留在若干年前嵌入式系统使用裸的FLASH芯片,需要自己管理这些繁杂事情的年代。

这里写图片描述

作为一篇科普贴,这篇文章的阅读对象是对当今的FLASH和SSD不甚了解的朋友们,而并不是那些存储界的老鸟们^_^

首先说下nand flash的种类,当今的nand flash主要分为三种:slc、mlc和tlc。slc每个cell存储一个bit,可以表示0或者1。mlc每个cell存储两个bit,可以表示0-3。tlc每个cell存储三个bit,可以表示0-7。
这里写图片描述

先说说最简单的slc,它是怎么实现一个bit的存储的。看下图,四个黑点是可以加压的地方。floating gate周围包围着一层绝缘层,在初始状态下(也就是擦除状态下),floating gate里没有电子,表示逻辑1。
这里写图片描述

对这个cell编程就是把这个cell写成逻辑0,这时需要在control gate加高压,在substrate接地,使得电子被强行打穿绝缘层进入floating gate,并被一直困在里面。
这里写图片描述

而擦除动作就是逆向操作,在substrate加高压,在control gate接地,使得困在floating gate的电子得以释放,恢复逻辑1。
这里写图片描述

在读操作的时候,往source和drain两边加压,假如floating gate里有电子,会使得这个电路断路,代表逻辑0。
这里写图片描述

而假如floating gate里没有电子,则会使得这个电路导通,代表逻辑1。
这里写图片描述

这样,我们就可以通过往source和drain加压后电路是否导通来判断这个cell存储的是1还是0了。譬如这里加上2V的电压,能通就代表逻辑1,不通就代表逻辑。
这里写图片描述

mlc把打入电子这个动作做得更为精确细腻了,所以通过把电压的区间划分为更精细的四段来表示11、10、01和00。读操作的时候,会尝试1V、2V和3V三次,根据能否导通来确定cell里面存储的值。tlc亦是如此,只是区间变成了8段。
这里写图片描述

刚才看的一直是一个cell,这里我们可以看到,横向的同一个word line上的cell组成了一个page,写操作的最小操作单元就是一个page。一共有多少个word line就代表这个block上有多少个page,擦除操作的最小操作单元就是一个block。
这里写图片描述

看了那么多的nand flash原理了,我们来看看实际的产品。这里要介绍几个概念就是package、target、lun(有的地方叫die,一个意思)。package你可以理解为我们日常能见到的封装好的PCB板上的flash芯片。package里包含一个或多个target,每个target独享物理管脚譬如ce、data[7:0],所以各个target之间是完全并行独立的。然后一个target里又可以包含一个或多个lun,lun也是可以独立运行的单元,和target的区别在于lun之间共享物理管脚。
这里写图片描述

再看一个lun里有可以有一个或者多个plane,plane也是可以独立运行命令的单元。所以总结一下,一块flash芯片,通常来说,容量越大,target、lun、plane就越多,性能就越好,因为这些物理单元都可以独立并行工作,使得效率最大化。这也就使得我们买的手机,自带的存储空间越大,性能就可能越好,其实就是越贵约好了,哈哈!
这里写图片描述

这里还要补充几个知识点,有些数据有了很大变化,有些则是文档里没有,靠经验口口相传的结论:

  • 大家都知道nand flash要擦了之后才可以写,但是大家知道吗,现在的mlc的擦写次数已经和我们在书本里学到的有天壤之别了。以前看到的什么slc几十万次,mlc几万次那已经一去不复返了。由于flash的制造工艺的提升,晶体管越做越小。好处是flash的容量越来越大,但是带来一个问题就是之前提到的floating gate周围的绝缘层也越来越薄。电子每次被加压强行穿过的时候,对绝缘层都会有一定的损伤。以前绝缘层厚,所以能擦写几万次,而现在的mlc一般只有可怜的3000(3k)次左右。有的2d的tlc更是到了惨不忍睹的300次。说到2d,那大家肯定会猜是不是还有3d。没错,由于工艺的提升,到的一定的程度,flash的耐久度到了极限了,于是以三星为代表的flash厂家想出了一个应对方法,就是把电路垂直往上叠,这样的话,就可以在总容量不变的情况下,把工艺降低。这样,容量也有了,耐久度也有了。所以3d tlc的擦写次数又回到了两三千次。
  • 擦写次数并不是说标的3000,就是擦写了3000次就坏了。有人做过实验,实际可以擦写几万次,还能正常工作。那这标的3000次又有什么意义那?还要说到那个绝缘层,虽然绝缘层能困住大部分的电子,但是其实还是会有很少一部分电子偷偷跑出来的。随着时间的推移,譬如半年一年之后,这个cell里的电子可能已经少了很多,而导致读出来的数据发生了错误。这就是flash的retention能力。每个厂商都会定一个这样的时间,3000次的擦写次数的意义就在于保证了在这3000次以内,retention能力是不会下降到可接受范围以外的。超过了3000次,cell不会坏,但是retention能力会下降。假如真的擦写了几万次之后一个block还能正常工作,那估计它的retention已经惨不忍睹了。

所以我们感觉到android系统用久了变慢,我能想到的和存储相关的几点就是:

  • flash确实发生了老化,不一定就是坏块了,单至少稳定性变差、出错概率变高,虽然通过bch、ldpc等纠错算法可以恢复,但是需要的时间变长了。
  • 由于存储卡越用越满,后期发生的写操作带来巨大的写放大,严重影响性能。说到写放大,先要介绍一个名词叫预留空间(Over provisioning),就是说预留一部分存储空间不保存数据。默认情况下,由于1024和1000的误差,至少会有7%多一点点的OP存在,记住,没有OP,SSD是不能工作的,或者说即使可以勉强工作,效率也很差。为什么这么说那?主要就是因为nand flash以块擦以页写的特性。假设我们用零OP,那倒最后,所有的block上所有的page保存的都是有用的数据。当我们想要更新当中某个page,由于不能直接覆盖写,我们需要把整个block腾出来,然后擦掉它,再把更新好的数据写回去。从上面的图可以看到,现在一个block的大小有2MB(还有更大的)。对有DRAM的SSD而言,也许还能把这个block的数据缓存在DRAM中,但对没有DRAM的低端SSD和emmc这种设备,根本不会有那么大的ram来缓存这些数据,那就陷入了死循环了。所以我们必须预留OP来做垃圾回收。
    这里写图片描述

    OP是可以改变的,有的是厂商改,有的则是开放给了用户改(譬如我家里的三星ssd),但是猜想emmc给用户改OP的概率不大。
    这里写图片描述
    那如何提升性能哪?接下来就可以介绍写放大(Write amplification)了。写放大的定义就是主机要写一份数据,而由于flash按块擦按页写的特性,N份数据需要挪动到新的物理位置。最后ssd主控为了实现主机的一份写而真是操作了N+1份写,那写放大就是N+1倍。那到底为什么会这样那?譬如我们就拿7%的OP来举例。在长期使用之后,我们可以认为有用的数据和脏数据是很均匀的分部在flash上的。所以在满盘的情况下,一个block假设如上图有256个page,那差不多是238个存着有用的数据,而18(7%*256)个存着已经不要了的垃圾数据。为了写新数据,就需要搬动老的数据。此时,不论盘有多满,固件必须保证有一个block是空的,然后就把刚才那个block的238个有用page搬过来,再在后面写入新的page,当然,之前那个block则又可以擦除了。为了写这18个page,固件实际写了256个page,写放大十几倍,性能就非常的差了,flash的寿命也会下降比较快。

  • 由于长时间的使用,原本连续的一个文件的内容已经分部在多个不同的物理位置了,导致读取时间变长。

然而对于这些,kernel已经完全被屏蔽了,kernel读写emmc,只会告诉它想要读写的逻辑地址LBA,emmc的FTL(Flash translation layer)负责把这个逻辑地址转换为真正nand上的物理地址。连真正的地址都不知道的kernel,完全就是透明的了。而且现在的nand flash存在着各种坑,emmc这种形式的好处就是把需要关心的细节留给了emmc的固件开发人员。所谓术业有专攻,把这些复杂的东西留给专业的人搞,其实是个不错的选择,要不然广大手机厂商还要自己关心这些细节,负担大了不说,做出来的性能也不见得更好。

最后给出一张很权威很经典的图。linux的存储系统要做优化,从kernel层面我觉得可行的是自上而下优化file system、block layer、mmc driver。但是具体细节我也不懂,感叹一声学无止尽啊!
这里写图片描述

以上是关于Android存储系统如何优化?的主要内容,如果未能解决你的问题,请参考以下文章

Android Bitmap的使用及优化

Android性能优化:内存优化

百度手机助手存储资源优化实践

SpUtil多样加密存储,兼容android9.0

android获取设备唯一ID(优化方案)

Android 内存I/O网络存储的优化实践