Android ViewHolder未正确回收导致Bitmap驻留堆内存问题求助
问题核心根源
你标记的几个传入ViewHolder的参数不是问题根源,内存暴涨由以下三个原因共同导致:
- 图片加载绑定了错误的生命周期:你传入的是Fragment级别的
viewLifecycleOwner,其生命周期远长于单个ViewHolder的存活周期。滚动过程中被回收的ViewHolder对应的图片加载请求不会被主动取消,所有请求都会执行完毕,产生的Bitmap没有对应的展示场景也无法及时回收,堆内存中就会堆积大量无效Bitmap实例。 - ViewHolder复用阶段没有清理任务:ViewHolder被复用执行新的
bind逻辑时,上一轮绑定触发的图片请求仍在运行,执行完成后会将Bitmap塞给已经被复用的ImageView,进一步增加无效Bitmap的数量,滚动频次越高,无效请求的数量就越大。 - 双层内存缓存重复存储:你自行实现的Lru联系人头像缓存,和Coil/Glide默认开启的内存缓存各自存储了一份相同的Bitmap,同一张图片直接占用双倍内存,进一步推高了内存占用。
修复方案
- 主动回收ViewHolder对应的图片请求
在Adapter中重写onViewRecycled方法,触发ViewHolder的资源释放逻辑:
override fun onViewRecycled(holder: RecyclerView.ViewHolder) { super.onViewRecycled(holder) if (holder is CustomerViewHolderPhoto) { holder.release() } }
在CustomerViewHolderPhoto的release方法中取消当前ImageView的加载请求,清空引用的Drawable:
override fun release() { // 取消当前ImageView对应的未完成加载请求 imageManager.cancelRequestForImageView(binding.imageViewCustomer) // 清空Bitmap引用,加速GC回收 binding.imageViewCustomer.setImageDrawable(null) }
- 解决缓存重复问题
二选一即可:
- 关闭图片库的内存缓存,以你自行实现的Lru缓存作为唯一内存缓存,比如Coil单次请求配置如下:
imageView.load(data) { memoryCachePolicy(CachePolicy.DISABLED) }
- 移除自行实现的Lru缓存,将
lookupKey作为图片加载的唯一缓存Key,交由Coil/Glide统一处理内存缓存,从根源避免重复存储。
- 优化Bitmap复用逻辑
检查你的ImageManager实现,避免每次加载都新建Bitmap实例,对接Coil/Glide的BitmapPool复用已回收的Bitmap内存空间,减少频繁的内存分配开销。
内容的提问来源于stack exchange,提问作者Andre Thiele
相关产品推荐
相关产品推荐

