写点什么

深入理解 Android 缓存机制 (一) 缓存简介,移动端应用开发

作者:嘟嘟侠客
  • 2021 年 11 月 28 日
  • 本文字数:2322 字

    阅读完需:约 8 分钟

辅助存储器

辅助存储器又称外存储器,简称外存,对于电脑而言,通常说的是硬盘或者光盘等,对于手机一般指的是 SD 卡,不过现在很多厂商都已经整合在一起了

缓存类型

  • 内存缓存:这里的内存主要指的存储器缓存

  • 磁盘缓存:这里主要指的是外部存储器,电脑指的是硬盘,手机的话指的就是 SD 卡

缓存容量

就是缓存的大小,到达这个限度之后,那么就需要进行缓存清理了

缓存策略

不管是内存缓存还是磁盘缓存,缓存的容量都是有限制的,所以跟线程池满了之后的线程处理策略类似,缓存满了的时候,我们也需要有相应的处理策略,常见的策略有:


  • FIFO(first in first out):先进先出策略,类似队列。

  • LFU(less frequently used):最少使用策略,RecyclerView 的缓存采用了此策略。

  • LRU(least recently used):最近最少使用策略,Picasso 在进行内存缓存的时候采用了此策略。


当缓存容量达到设定的容量的时候,会根据制定的策略进行删除相应的元素。

内存泄露

这个主要发生在内存缓存中,当生命周期段的对象持有了生命周期长的对象的引用就会发生内存泄露,解决这种问题通常有两种方式


  • 引用置空:将缓存中引用的对象置空,然后 GC 就能够回收这些对象

  • 采用弱引用:采用弱引用关联对象,这样就能够不干涉对象的生命周期,以便 GC 能够正常回收


实际上在防止内存泄露的过程中这两种方式都使用地比较平凡,不过我们大多数时候使用的还是弱引用。


其实 Java 有四种引用,强引用,软引用,弱引用,虚引用,这些并没什么好说的,我们平时使用最多的还是弱引用,也就是 WeakReference。


弱引用 VS 软引用


只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。


下面简单描述一下这两种防止内存泄露的方法的区别

引用置空

RecyclerView 的内部类 LayoutManager 持有了 RecyclerView 的使用,没有采用弱引用,但是提供了置空的方法


public static abstract class LayoutManager {ChildHelper mChildHelper;RecyclerView mRecyclerView;@NullableSmoothScroller mSmoothScroller;private boolean mRequestedSimpleAnimations = false;boolean mIsAttachedToWindow = false;private boolean mAutoMeasure = false;private boolean mMeasurementCacheEnabled = true;private int mWidthMode, mHeightMode;private int mWidth, mHeight;


void setRecyclerView(RecyclerView recyclerView) {if (recyclerView == null) {//回收 mRecyclerView = null;mChildHelper = null;mWidth = 0;mHeight = 0;} else {//初始化 mRecyclerView = recyclerView;mChildHelper = recyclerView


《Android 学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享


.mChildHelper;mWidth = recyclerView.getWidth();mHeight = recyclerView.getHeight();}mWidthMode = MeasureSpec.EXACTLY;mHeightMode = MeasureSpec.EXACTLY;}

采用弱引用

用 Picasso 中的 Action 为例,父类采用了 WeakReference



Action 父类


abstract class Action<T> {final WeakReference<T> target;Action(Picasso picasso, T target, Request request, int memoryPolicy, int networkPolicy,int errorResId, Drawable errorDrawable, String key, Object tag, boolean noFade) {this.picasso = picasso;this.request = request;this.target =target ;this.memoryPolicy = memoryPolicy;this.networkPolicy = networkPolicy;this.noFade = noFade;this.errorResId = errorResId;this.errorDrawable = errorDrawable;this.key = key;this.tag = (tag != null ? tag : this);}


ImageAction 子类


class ImageViewAction extends Action<ImageView> {Callback callback;ImageViewAction(Picasso picasso, ImageView imageView, Request data, int memoryPolicy,int networkPolicy, int errorResId, Drawable errorDrawable, String key, Object tag,Callback callback, boolean noFade) {super(picasso, imageView, data, memoryPolicy, networkPolicy, errorResId, errorDrawable, key,tag, noFade);this.callback = callback;}


@Override public void complete(Bitmap result, Picasso.LoadedFrom from) {if (result == null) {throw new AssertionError(String.format("Attempted to complete action with no result!\n%s", this));}


ImageView target = this.target.get();if (target == null) {return;}Context context = picasso.context;boolean indicatorsEnabled = picasso.indicatorsEnabled;PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);}


由于 ImageView 持有 Context 的引用,所以导致 Activity 回收之后,如果 ImageView 是强引用,那么 GC 就不会去回收,而采用了弱引用之后,一旦 Activity 被回收,那么 ImageViewAction 的引用不会干扰到 Activity 的回收。

缓存时间

文末

那么对于想坚持程序员这行的真的就一点希望都没有吗?其实不然,在互联网的大浪淘沙之下,留下的永远是最优秀的,我们考虑的不是哪个行业差哪个行业难,就逃避掉这些,无论哪个行业,都会有他的问题,但是无论哪个行业都会有站在最顶端的那群人。我们要做的就是努力提升自己,让自己站在最顶端,学历不够那就去读,知识不够那就去学。人之所以为人,不就是有解决问题的能力吗?挡住自己的由于只有自己。Android 希望=技能+面试


  • 技能

  • 面试技巧+面试题


本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

用户头像

嘟嘟侠客

关注

还未添加个人签名 2021.03.19 加入

还未添加个人简介

评论

发布
暂无评论
深入理解Android缓存机制(一)缓存简介,移动端应用开发