fresco源码分析-软引用的黑科技

32 篇文章 0 订阅

           我们知道从Android2.*后google不推荐使用软饮用了, 因为google优化了gc回收机制, 每次gc时不管内存是否充足都会释放软引用。 google推荐使用LruCache.java替代软引用, 而LruCache内部维护个LinkedList, 实际上就是当内存不足时删掉最远使用的对象。

       在分析fresco内存相关的源码时, 可以到有个类叫OOMSoftReferecne, 使用3个SoftReference指向同一个对象。 看最后一句翻译过来就是“只有在OOM时才会释放这个引用”TLDR: It's a reference that's cleared if and only if we otherwise would have encountered an OOM. 翻译过来就是“只有在OOM时才会释放这个引用”, 多个软引用放到一起相当于强引用了惊讶

/**
 * To eliminate the possibility of some of our objects causing an OutOfMemoryError when they are
 * not used, we reference them via SoftReferences.
 * What is a SoftReference?
 *    <a href="http://developer.android.com/reference/java/lang/ref/SoftReference.html"></a>
 *    <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/ref/SoftReference.html"></a>
 * A Soft Reference is a reference that is cleared when its referent is not strongly reachable and
 * there is memory pressure. SoftReferences as implemented by Dalvik blindly treat every second
 * SoftReference as a WeakReference every time a garbage collection happens, - i.e. clear it unless
 * there is something else referring to it:
 *  <a href="https://goo.gl/Pe6aS7">dalvik</a>
 *  <a href="https://goo.gl/BYaUZE">art</a>
 * It will however clear every SoftReference if we don't have enough memory to satisfy an
 * allocation after a garbage collection.
 *
 * This means that as long as one of the soft references stays alive, they all stay alive. If we
 * have two SoftReferences next to each other on the heap, both pointing to the same object, then
 * we are guaranteed that neither will be cleared until we otherwise would have thrown an
 * OutOfMemoryError. Since we can't strictly guarantee the location of objects on the heap, we use
 * 3 just to be on the safe side.
 * TLDR: It's a reference that's cleared if and only if we otherwise would have encountered an OOM.
 */
public class OOMSoftReference<T> {

  SoftReference<T> softRef1;
  SoftReference<T> softRef2;
  SoftReference<T> softRef3;

  public OOMSoftReference() {
    softRef1 = null;
    softRef2 = null;
    softRef3 = null;
  }

  public void set(@Nonnull T hardReference) {
    softRef1 = new SoftReference<T>(hardReference);
    softRef2 = new SoftReference<T>(hardReference);
    softRef3 = new SoftReference<T>(hardReference);
  }

  @Nullable
  public T get() {
    return (softRef1 == null ? null : softRef1.get());
  }

  public void clear() {
    if (softRef1 != null) {
      softRef1.clear();
      softRef1 = null;
    }
    if (softRef2 != null) {
      softRef2.clear();
      softRef2 = null;
    }
    if (softRef3 != null) {
      softRef3.clear();
      softRef3 = null;
    }
  }
}
      为了验证上述说法, 我写个简单的demo。

public class MainActivity extends AppCompatActivity {
    SoftReference<?> softReference1;
    SoftReference<?> softReference2;
    SoftReference<?> softReference3;
    TextView tvTest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Bitmap bmp = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888);
        Log.d("brycegao", "bitmap size:" + bmp.getByteCount());

        softReference1 = new SoftReference<Bitmap>(bmp);
        //softReference2 = new SoftReference<Bitmap>(bmp);
        //softReference3 = new SoftReference<Bitmap>(bmp);

        tvTest = (TextView) findViewById(R.id.tv_test);
        tvTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                System.gc();   //强制内存回收
                Object obj = softReference1.get();
                Log.d("brycegao", "softreference:" + obj);
            }
        });
    }
}

09-03 09:21:15.371 6530-6530/com.example.brycegao.myapplication D/brycegao: bitmap size:16777216
09-03 09:21:15.502 6530-7062/com.example.brycegao.myapplication V/RenderScript: 0x9ffde000 Launching thread(s), CPUs 4
09-03 09:21:24.872 6530-6530/com.example.brycegao.myapplication D/brycegao: softreference:null

       从日志可以看出只有一个软饮用指向bitmap时, gc时会回收这块内存的。 

       放开softReference2,softReference3的注释, 即使用3个软饮用再次测试:

09-03 09:37:19.621 23036-23036/com.example.brycegao.myapplication D/brycegao: bitmap size:16777216
09-03 09:37:30.462 23036-23036/com.example.brycegao.myapplication D/brycegao: softreference:android.graphics.Bitmap@3067335

       果然!!! 软饮用指向的大图片没被回收, 以后在项目管理内存时可以使用这种做法, 即多个软饮用指向同一个对象大笑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值