问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

大文件高速图片缓存技术在Android手机相册里面的应用

创作时间:
作者:
@小白创作中心

大文件高速图片缓存技术在Android手机相册里面的应用

引用
1
来源
1.
https://www.bilibili.com/opus/918588578580135938

Android手机相册应用的用户体验在很大程度上取决于图片的加载速度。现有的图片缓存技术如Glide,由于在大量图片加载过程中频繁的磁盘I/O操作导致性能瓶颈,当用户快速浏览时难以保持流畅性。本文提出了一个优化方案,该方案通过集成大文件存储和高效索引机制,显著提升了图片加载速度,并提出了一种基于栈的加载模型以进一步优化用户滑动浏览时的响应速度。

常用的图片缓存技术存在的一些问题

Glide缓存的图片是分散在磁盘各个区域,每加载一张图片就需要打开文件句柄,读取,关闭。并且存储的图片都是压缩的,读取之后需要进行解码。在计算机中磁盘的I/O操作是比较耗时的,即使现在手机用的是闪存技术,在相册这种需要大批量加载图片的应用,过于频繁的I/O操作,响应依然是慢的。

另外Glide的图片缓存是基于LRU算法策略,在手机相册中场景中并不适用这种策略,相册中大多数场景是连续,线性的浏览图片,需要新的设计适应这种场景。

大文件图片缓存技术的实现方案

  1. 缩略图大文件化

确定了性能瓶颈就是频繁的磁盘的I/O,如何优化这个问题就需要从这方面入手。借鉴Google的GFS(Google File System)大文件系统的设计方案,通过将所有图片的缩略图,以标准的大小,比如50*50像素(相册中展示的网格图片每一格子的缩略图图一般都是正方形),将原始的RGB像素数据存储为一个大文件。相册中的图片浏览一般都是按日期排序的连续图片,可以针对这个特点以图片时间排序生成大文件。图片在大文件中的分布是连续的。可以保持一个文件句柄在内存中不释放,通过文件的句柄移动来大批量的读取图片文件,这样就避免频繁打开和关闭文件句柄。在磁盘的I/O操作中一次读取1kb和一次读取1mb的数据,时间消耗是差不多的。

由于存储的是像素,可以直接生成内存中的位图数据,无需解码过程。通过这些方法优化可以极大提升图片的加载速度。

  1. 构建大文件分页的B树搜索索引

通过大文件中连续存储的图片,可以对大文件进行分页,比如以10张图片作为一页,并构建B树索引。每个叶子节点就是一页,存储了页在大文件中的起始位置和长度。比如在检索一个时间区间内的所有图片,可以将时间区间传入B树索引进行检索,最终得到需要加载的页,再通过文件句柄的移动在大文件中加载相应的图片。也就是说在这个模型下图片是一页一页进行加载的。

  1. 大文件的碎片整理以及B树再平衡

这个方案有个致命的问题,就是需要对图片进行增删,当要删除某个图片时,由于图片可能在大文件的任意位置,在删除图片就需要找到相应位置,并删除这部分数据,然后重新合并大文件。另外在增加时也有可能需要在大文件中进行插入。这些操作代价无疑是很高昂的。解决的方法就是当需要删除时将该区域的数据标识为已删除,在增加图片是无论排序的位置是哪里,都要追加至大文件尾部。

但即便做到这些依然会有碎片化的问题,当删除的图片越来越多,以及不按排序追加的图片越来越多,大文件中的图片就不连续了,会降低图片加载的性能。解决的办法就是当大文件的无序程度(熵)达到一定程度的时候进行碎片整理,使得大文件重新变得有序。这是一个耗时的操作,不仅要操作大文件,还是需要对B树进行再平衡,需要谨慎处理。

  1. 大文件分割与并行I/O访问

当图片越来越多,致使大文件越来越膨胀,也会影响性能。可以参考GFS的Chunk模型,将大文件分块进行存储,每个文件作为一个chunk块并保留文件句柄,这样做的好处是在碎片整理的时候复杂度会降低,同时现在的手机用的都是闪存,对并行访问也有不错的支持,图片的加载的性能也会提升。但这样会增加系统的复杂度以及开发难度。

  1. 基于栈的图片加载模型

在大多数图片缓存系统中,图片加载的任务一般都是放在队列里面挨个进行加载的,但在相册中,用户快速滑动时,往往需要优先加载当前位置的相关图片,所以可以把队列换成栈,用栈先进先出的特点,优先加载当前位置的图片,当加载到离当前位置比较远的,直接进行丢弃不进行加载了。这样也可以达到优化用户体验的效果。

缺点

假如需要加载的图片比较分散,加载时句柄需要不停寻址,就会导致性能下降。举个最差的例子,假如要加载的图片是分布在大文件索引的每个页中,那么加载时整个大文件都需要加载一遍。针对这个问题目前还没有完美的解决方案的。但依然有优化的点。

在对大文件进行分页的时候,对分页的大小进行权衡,让加载一页的耗时和加载一张图片的耗时差不多就可以优化这个问题。这里再次强调一下,磁盘加载1kb的数据和加载1mb的数据耗时可能差不多的。

总结

总的优化原则就是减少磁盘I/O次数;将随机访问变为顺序访问;将零散的加载变为批量加载;减少解码过程;以空间换时间。

  • 缩略图大文件化:

  • 统一存储:将所有缩略图以标准大小统一存储在一个连续的大文件中。

  • 时间序列排列:图片按某种规则排序,保证大文件中的连续性。

  • 常驻句柄:在内存中维护常开的文件句柄,减少文件访问的开销。

  • B树分页索引:

  • 分页机制:按照一定数量对大文件进行分页。

  • B树索引:构建B树索引来搜索这些分页,实现快速查找和定位。

  • 动态数据管理和碎片整理:

  • 标记删除:在删除图片时,仅在索引中标记该图片为已删除状态,而不立即从文件中物理删除。

  • 尾部追加:新增图片统一追加到大文件的末尾,无论其时间顺序,避免中间插入引起的文件重组。

  • 定期优化:当大文件的无序程度达到一定阈值时,执行碎片整理,重建文件和B树索引的顺序。

  • 基于栈的加载模型:

  • 栈式处理:将图片加载任务由队列更改为栈,实现后进先出,优先加载用户当前视图相关的图片。

  • 距离判断丢弃:对于距离当前浏览位置较远的图片加载任务,选择丢弃以节省资源。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号