fresco源码分析-内存回收

           我觉得内存管理是三方图库最重要的点, 而且该知识点能够应用到项目里, 所以着重看了一下fresco是如何回收内存的。

      fresco内存释放分为2种方式:

 1、按照LruCach的方式释放引用计数为0对象, fresco内部逻辑实现;

 2、应用退到后台、手机低内存等场景下主动释放fresco的内存, 包括引用计数不为0的对象, 需要传事件给fresco。 参考: https://github.com/facebook/fresco/issues/1457

ImagePipeline imagePipeline = Fresco.getImagePipeline();
imagePipeline.clearMemoryCaches(); //内存,包括已解码和未解码
imagePipeline.clearDiskCaches();   //删除文件

// combines above two lines
imagePipeline.clearCaches();


                                         qfyyziz.png

          上图是fresco官方提供的架构图, 按照三级缓存。 即已解码的图片,未解码的图片和文件缓存。Android5.0以前bitmap是缓存在ashmem里, Android5.0及以上保存在java堆里。 为了释放bitmap, fresco定义了引用计数类SharedPrefrence。

public class SharedReference<T> {

  // Keeps references to all live objects so finalization of those Objects always happens after
  // SharedReference first disposes of it. Note, this does not prevent CloseableReference's from
  // being finalized when the reference is no longer reachable.
  @GuardedBy("itself")
  private static final Map<Object, Integer> sLiveObjects = new IdentityHashMap<>();

  @GuardedBy("this")
  private T mValue;
  @GuardedBy("this")
  private int mRefCount;

  private final ResourceReleaser<T> mResourceReleaser;

  /**
   * Construct a new shared-reference that will 'own' the supplied {@code value}.
   * The reference count will be set to 1. When the reference count decreases to zero
   * {@code resourceReleaser} will be used to release the {@code value}
   * @param value non-null value to manage
   * @param resourceReleaser non-null ResourceReleaser for the value
   */
  public SharedReference(T value, ResourceReleaser<T> resourceReleaser) {
    mValue = Preconditions.checkNotNull(value);
    mResourceReleaser = Preconditions.checkNotNull(resourceReleaser);
    mRefCount = 1;
    addLiveReference(value);
  }

  /**
   * Increases the reference count of a live object in the static map. Adds it if it's not
   * being held.
   *
   * @param value the value to add.
   */
  private static void addLiveReference(Object value) {
    synchronized (sLiveObjects) {
      Integer count = sLiveObjects.get(value);
      if (count == null) {
        sLiveObjects.put(value, 1);
      } else {
        sLiveObjects.put(value, count + 1);
      }
    }
  }

  /**
   * Decreases the reference count of live object from the static map. Removes it if it's reference
   * count has become 0.
   *
   * @param value the value to remove.
   */
  private static void removeLiveReference(Object value) {
    synchronized (sLiveObjects) {
      Integer count = sLiveObjects.get(value);
      if (count == null) {
        // Uh oh.
        FLog.wtf(
            "SharedReference",
            "No entry in sLiveObjects for value of type %s",
            value.getClass());
      } else if (count == 1) {
        sLiveObjects.remove(value);
      } else {
        sLiveObjects.put(value, count - 1);
      }
    }
  }

  /**
   * Get the current referenced value. Null if there's no value.
   * @return the referenced value
   */
  public synchronized T get() {
    return mValue;
  }

  /**
   * Checks if this shared-reference is valid i.e. its reference count is greater than zero.
   * @return true if shared reference is valid
   */
  public synchronized boolean isValid() {
    return mRefCount > 0;
  }

  /**
   * Checks if the shared-reference is valid i.e. its reference count is greater than zero
   * @return true if the shared reference is valid
   */
  public static boolean isValid(SharedReference<?> ref) {
    return ref != null && ref.isValid();
  }

  /**
   * Bump up the reference count for the shared reference
   * Note: The reference must be valid (aka not null) at this point
   */
  public synchronized void addReference() {
    ensureValid();
    mRefCount++;
  }

  /**
   * Decrement the reference count for the shared reference. If the reference count drops to zero,
   * then dispose of the referenced value
   */
  public void deleteReference() {
    if (decreaseRefCount() == 0) {
      T deleted;
      synchronized (this) {
        deleted = mValue;
        mValue = null;
      }
      mResourceReleaser.release(deleted);
      removeLiveReference(deleted);
    }
  }

  /**
   * Decrements reference count for the shared reference. Returns value of mRefCount after
   * decrementing
   */
  private synchronized int decreaseRefCount() {
    ensureValid();
    Preconditions.checkArgument(mRefCount > 0);

    mRefCount--;
    return mRefCount;
  }

  /**
   * Assert that there is a valid referenced value. Throw a NullReferenceException otherwise
   * @throws NullReferenceException, if the reference is invalid (i.e.) the underlying value is null
   */
  private void ensureValid() {
    if (!isValid(this)) {
      throw new NullReferenceException();
    }
  }

  /**
   * A test-only method to get the ref count
   * DO NOT USE in regular code
   */
  public synchronized int getRefCountTestOnly() {
    return mRefCount;
  }

  /**
   * The moral equivalent of NullPointerException for SharedReference. Indicates that the
   * referenced object is null
   */
  public static class NullReferenceException extends RuntimeException {
    public NullReferenceException() {
      super("Null shared reference");
    }
  }
}

       这个类中有这么两个重要方法:addReference()和deleteReference(),通过这两个基本方法来对引用进行计数,一旦计数为零时,则调用ResourceReleaser的release方法(调用了如:nativeFree、删除引用或Bitmap.recycle()等)。

         在Android5.0后Fresco又封装了CloseableReference类实现了Cloneable、Closeable接口,它在调用.clone()方法时同时会调用addReference()来增加一个引用计数,在调用.close()方法时同时会调用deleteReference()来删除一个引用计数。 fresco对CloseableReference的注释:This class allows reference-counting semantics in a Java-friendlier way. A single object can have any number of CloseableReferences pointing to it. When all of these have been closed, the object either has its {@link Closeable#close} method called, if it implements {@link Closeable}, or its designated {@link ResourceReleaser#release}。 翻译过来就是CloseReference

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值