最容易被忽略的性能洼地-磁盘

最容易被忽略的性能洼地-磁盘

数据库随机读/写是相对顺序读/写而言的,在读取或者写入的时候会随机产生offset。

随机读写例子,如果向设置了autoincrement的数据库表中插入多条数据,那么每插入一条数据,都需要操作两张数据库表,这就意味着存在随机写。

随机写相对于顺序写除了会产生大量的时效页面外,更重要的是增加了触发“写入放大”效应的概率。

简单的例子,比如现在写入一个4kb的数据,最坏的情况就是,一个块里已经没有干净空间,但恰好有一个页的无效数据可以擦除,所以主控就把所有的数据读取出来,擦除块,再加上这个4kb的新数据写回去。其实只是想写4kb的数据,结果造成了整个块512kb的写入操作,这就造成延迟大大增加,速度慢是自然的。

数据库操作最终操作的是磁盘上的DB文件,Db文件和普通文件本质上并无差异,而I/O系统的性能一直是计算机的瓶颈,所以优化数据库最终落脚点往往在如何减少磁盘I/O上。

无论是优化表结构、使用索引、增加缓存、调整page size等,最终目的都是减少磁盘I/O操作。这些都是常规的优化数据库的手段。

我们知道每次打开、关闭或者读写文件件,操作系统都需要从用户态到内核态的切换,这种状态的切换本身是很消耗性能的,所以为了提高文件的读写效率,这就需要尽量减少用户态到内核态的切换。

比如使用缓存可以避免重复读写,对于需要多次访问的数据,在第一次读取数据时,将数据放到缓存中,下次在访问这些数据时,就可以从缓存中取出来。

总而言之,针对磁盘的性能优化就是在I/O操作上的优化,主要分为三大方向:

一、避免主线程I/O

  1. 避免主线程操作文件和数据库。50%以上的卡顿问题都是由主线程I/O引起的。
  2. 用apply代替Sharepreference.commit。apply是异步操作,commit是同步操作。
  3. 提前初始化Sharepreference。在多线程和旧版本的Android中,初始化过程的I/O读写是在主线程的。

二、减少I/O的读写量

  1. 减少使用select*。减少从数据库读取的数据量,减少耗时。
  2. 利用缓存减少重复读写。内存缓存命中率极高,投入产出高。
  3. 数据库适度使用autoincrement。因为要多操作一个表,所以Insert耗时减少2-4倍。
  4. 使用合适的数据库分页。sqlite读写磁盘是以page为单位的,在3.12.0版本之前,sqlite默认page size是1kb,从3.12.0开始,page size调整为4kb。
  5. 频繁查询的表使用索引。索引可以极大地减少读磁盘的数据量,极大的提高效率。
  6. 避免无效索引。无效索引的问题通常是严重的。除了触发全表扫描,产生大量冗余的读写之外,还降低了写入性能。

三、减少I/O操作次数

  1. 使用8kb Buffer读写。可以减少2-3倍的耗时。
  2. 批量更新数据库使用事务。启用事务,根据业务规模,会大量减少I/O读写量和操作次数,从而提高效率。
  3. ZIP压缩大量小文件时建议使用zipInputStream。

Bitmap解码,Google没有告诉你的坑

随着Android SDK 的升级,Google修改了Bitmap解码API的实现,从而埋下了一个性能的坑。若是在Bitmap解码时,使用api不当就有可能造成I/O效率低的问题,这个坑就是:

  • 解码Bitmap不要使用decodeFile,因为在Android 4.4以上系统效率不高。
  • 解码Bitmap使用decodeStream,同时传入的文件流为BufferedInputStream。
  • decodeResurce同样存在性能问题,请用decodeResourceStream。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值