软引用是否会在Bitmap对象上调用.recycle()方法?

7
如果我使用SoftReference在HashMap中存储位图,SoftReference会调用Bitmap的.recycle()方法吗?如果不会,那么在给定情况下(当位图在HashMap中)清除位图的正确方法是什么?
4个回答

6

来自 Bitmap.recycle 文档:

This is an advanced call, and normally need not be called, 
since the normal GC process will free up this memory when there 
are no more references to this bitmap. 

因此,弱引用足以保持位图。如果由于某种原因需要强制释放此资源,则使用弱引用无法实现。
编辑
我不熟悉Android中的位图实现,但可能需要显式处理位图资源的原因是某些内存不是在堆上创建的。因此,在没有GC需求的情况下,进程可能会耗尽内存。想象一下,一个小对象持有从其他地方malloc的大内存块。对象的finalize可能准备释放内存,但VM没有GC的理由,因此本机内存“丢失”。
但在这种情况下,弱引用也无济于事,因为它仅在GC之后处理。唯一有用的方法是使用显式“回收”,也许可以借助引用计数来实现。

我同意这一点,没有任何定制工作应该是可以的。 - Thomas Vervest
如何从Bitmap类继承并覆盖finalize()方法? - 2cupsOfTech
你为什么要这样做?正如文档中所述,资源会在垃圾回收时被释放。Finalize 不会做任何其他事情(只会增加开销)。你的意图是什么? - mtraut
好的 - 在“位图”中可能存在(已知的)错误,因此文档中的语句不正确。在这种情况下,您应该查找相应的问题及其当前状态。但我不相信你会找到这样的问题。另一种可能性是其他用户有其他使用场景。也许他们强制引用位图实例并在使用后不清除引用。因此,他们必须进行"回收"。我只能从文档上告诉您,您什么也不需要做,只需不再引用该位图即可。我已经添加了一个注释在上面... - mtraut
你是对的。弱引用并不能帮助实现图像内存缓存,因为在蜂窝版本之前,图像的内存分配在堆外进行。 - HighFlyer

5
如果我使用SoftReference在hashmap中存储位图,那么SoftReference会调用Bitmap的.recycle()方法吗?
不会。如果你存储的是一个String或POJO而不是Bitmap,它们是否有recycle方法呢?当然没有。所以问题是:什么是SoftReference用途?
当您希望引用的对象保持活动状态直到托管进程内存不足时,可以使用SoftReference。对象只有在收集器需要释放内存时才会被收集。简单地说,绑定SoftReference意味着“在不能再绑定之前请让对象一直存在”。 (link
您不必关心清除位图(调用recycle方法);只需让SoftReference发挥作用就可以了。

5
我找不到 romainguy 的评论,他在评论中提到,如果你不调用 .recycle() 方法来清除位图,否则你会遇到内存问题。如果你去 android-dev 上问任何在 Android 上使用过位图的开发人员,他们都知道不调用 .recycle() 方法会导致问题出现。 - 2cupsOfTech
我同意2cupsOfTech的观点。虽然文档声称相反,但你绝对需要在Bitmap上调用recycle方法。否则,在堆大小较小的设备上会遇到麻烦。 - Apfelsaft

0

Bitmap的相关资源将在GC时通过它的finalize()方法被释放。如果您知道Bitmap不再需要,则可以使用recycle()方法立即释放资源,但这不是您的情况。您使用SoftReference因为您想在内存不足的情况下回收图像。


-1
如果WeakReference引用的对象将被GC回收,我会认为这会触发位图上的recycle方法。但是我不确定,所以为了安全起见,您可以做一些事情,例如覆盖WeakReference类,创建一个特定于位图的WeakReference类,在其引用被GC回收时调用recycle方法。
解决方案应该看起来像这样,但尚未经过测试:
private final class WeakBitmapReference extends WeakReference<Bitmap> {
    public WeakBitmapReference(Bitmap b) {
        super(b);
    }

    public void clear() {
        Bitmap b = get();
        if (b != null && !b.isRecycled())
            b.recycle();
        super.clear();
    }
}

很抱歉,这样做不会起作用。虚拟机在任何时候都不会调用“clear”。将其添加到引用队列中也行不通,因为“get”不再返回任何结果。 - mtraut

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接