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。但是具体细节我也不懂,感叹一声学无止尽啊!

时间: 2024-08-09 11:44:21

Android存储系统如何优化?的相关文章

Android存储系统的架构与设计

一.概述 本文讲述Android存储系统的架构与设计,基于Android 6.0的源码,涉及到最为核心的便是MountService和Vold这两个模块以及之间的交互.为了缩减篇幅,只展示部分核心代码. MountService:Android Binder服务端,运行在system_server进程,用于跟Vold进行消息通信,比如MountService向Vold发送挂载SD卡的命令,或者接收到来自Vold的外设热插拔事件.MountService作为Binder服务端,那么相应的Binde

Android的内存优化

腾讯公司在五月三十一日开展[腾讯Bugly移动开发者沙龙]大会,大会上面叶方正老师讲解了 关于Android的内存优化的问题,不过我感觉叶老师更多的站在了测试的角度上去解释了这一方面,叶老师给我们介绍了很多的工具去测试Android应用在各种情况下的内存占用情况,不过好像对我们开发的帮助并不是特别的大.我在这里总结叶老师所说的重点和自己对内存优化的一些理解,希望能够对大家有所帮助. Android应用优化主要集中在内存和UI流畅度上,从内存占用与泄露.UI流畅度的帧数和响应时间到IO的阻塞式响应

【读书笔记】《Android应用性能优化最佳实践》

<第一行代码>读书笔记 一.引言 二.读书内容 书名:<Android应用性能优化最佳实践> 作者:罗彧成 (腾讯音乐Android开发总监) 出版社:机械工业出版社 封面: 三.书籍评价 四.个人心得 五.参考文档

Android app性能优化大汇总之内存性能优化

写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上把网上搜集的各种内存零散知识点进行汇总.挑选.简化后整理而成. 所以我将本文定义为一个工具类的文章,如果你在Android开发中遇到关于内存问题,或者马上要参加面试,或者就是单纯的学习或复习一下内存相关知识,都欢迎阅读.(本文最后我会尽量列出所参考的文章). 内存简介: RAM(random access memory)随机存取存储器.说白了就是内存. 一般Java在内存分配时会涉及到以下区域: 寄存器(R

android shape图形优化Button效果

android shape可以让我们通过定义xml文件的方式创建图形,当然只能实现一些比较简单的图形(圆形,矩形,椭圆,线段),但是已经相当不错了,通过shape创建的图形作为控件的背景已经基本可以满足我的简单需求了,而且通过shape创建的图形可以适配各种屏幕. 下面就用shape定义的图形来优化Button的整体效果. 定义主布局文件activity_main.xml: 1 <RelativeLayout xmlns:android="http://schemas.android.co

Android App性能优化(一)之布局优化

当创建复杂布局的时候,我们会在xml 文件中添加大量的ViewGroup和View.伴随着每次迭代,View树的层次越来越深,界面加载速度越来越慢,消耗的内存也越来越多.当您的程序出现加载时短暂黑屏或横竖切换时短暂黑屏,抑或如内存溢出(OOM)之类的问题时,没准您的程序需要优化了. 那么如何让程序运行速度更快?响应更敏捷?优化布局是一个最基本的方法,本文将介绍最基本的优化布局方法. 1.使用ViewStub实现View的延迟加载. 很多情况下,xml布局文件中的部分View初始状态是设置为不显示

Android内存性能优化(内部资料总结)

刚入门的童鞋肯能都会有一个疑问,Java不是有虚拟机了么,内存会自动化管理,我们就不必要手动的释放资源了,反正系统会给我们完成.其实Java中没有指针的概念,但是指针的使用方式依然存在,一味的依赖系统的gc,很容易就造成了内存的浪费.   Java基于垃圾回收的内存机制 Java的内存管理机制会自动回收无用对象所占用的内存,减轻手工管理内存的负担 1.C/C++: 从申请.使用.释放都需要手工管理 2.Java:无用的对象的内存会被自动回收 什么样的对象是无用的对象 1.Java通过引用来操作一

Android代码内存优化建议-Android官方篇

转自:http://androidperformance.com/ http://developer.android.com/intl/zh-cn/training/displaying-bitmaps/index.html 为了使垃圾回收器可以正常释放程序所占用的内存,在编写代码的时候就一定要注意尽量避免出现内存泄漏的情况(通常都是由于全局成员变量持有对象引用所导致的),并且在适当的时候去释放对象引用.对于大多数的应用程序而言,后面其它的事情就可以都交给垃圾回收器去完成了,如果一个对象的引用不

Android开发性能优化总结(一)

安卓开发应用首先要讲究良好的用户体验,如果一款软件卡顿现象严重,不流畅,经常崩溃,那么将给用户带来极不良好的体验,从而损失用户. 在实际开发和学习中,我总结了一下关于安卓性能的优化,供大家参考交流. 应用程序的性能问题体现在很多方面, 比如第一次启动速度慢,或者进入某一界面速度慢:动画执行过程不流畅,或者动画执行卡顿时间长:ListView列表滑动过程中卡顿,不流畅:应用程序自定义的某特定界面执行速度慢:响应某一用户事件时长时间无响应(ANR):操作数据库时,执行大量数据的增删改查操作,执行速度