【问题标题】:Is there a way to tell if a Bitmap has been completely disposed on Android?有没有办法判断位图是否已在 Android 上完全处置?
【发布时间】:2011-10-01 10:50:39
【问题描述】:

我正在创建一个调用BitmapRegionDecoder.decodeRegion(Rect, BitmapFactory.Options) 的查看器应用程序。我正在处理每次调用之前从decodeRegion 获得的位图:

//this is a function I wrote that gets the rectangle I need
//from the zoom/pan state of a lower-resolution ImageView (page).
//it is bragable.
Rect areaRect = page.getBitmapRegionDecoderRect(areaBitmapRect);
BitmapFactory.Options options = new BitmapFactory.Options();

//area is the ImageView which will get the hi-res bitmap in it.
if(area.getHeight()!=0)
{
//I used Math.round because we are so desperate to save memory!
//The consequent blurring is actually not too bad.
    options.inSampleSize = Math.round( ((float) areaRect.height()) / ((float) area.getHeight()) );
}
else
{
    options.inSampleSize = Math.round( ((float) areaRect.height()) / ((float) page.getHeight()) );
}
if(options.inSampleSize==0) options.inSampleSize=1;
if(options.inSampleSize>16) options.inSampleSize=16;
options.inPreferredConfig = Bitmap.Config.RGB_565;
if(areaRect.left<0) areaRect.left = 0;
if(areaRect.right>areaBitmapRect.right) areaRect.right = areaBitmapRect.right;
if(areaRect.top<0) areaRect.top = 0;
if(areaRect.bottom>areaBitmapRect.bottom) areaRect.bottom = areaBitmapRect.bottom;
if(areaBitmap!=null)
{
//recycling our garbage ... or are we?
    areaBitmap.recycle();
    areaBitmap = null;
    try
    {
//dirty hack
        wait(200);
    }
    catch(Exception x)
    {
//something happened.
    }
}
//the all-important call
areaBitmap = areaDecoder.decodeRegion(areaRect, options);
area.setImageBitmap(areaBitmap);

我遇到了一个问题,即在非常快速的连续 UI 事件中,内存不足。正如你所看到的,我已经用肮脏的黑客“解决”了这个问题(线程等待 200 毫秒并给 Android 一点时间赶上)。

出于显而易见的原因,我对此不太满意。首先,我的诊断(在我们分配新内存之前垃圾收集没有完成)是否正确?其次,我试着把

while(!areaBitmap.isRecycled())

recycle() 调用之后计数器增加一个,并且计数器保持为零。我看到让isRecycled() 这样做的意义,但我需要类似isCompletelyRecycled() 的方法。 Android有这样的东西吗?第三,如果我对此无能为力,是否有一种“可用内存”方法可以用来判断我的电话是否会将我们推倒?我找不到一个。如果 Android 会说更多核心可用但对你没有,那就太好了,所以我可以将我的等待循环称为 B 计划,或者最终尝试一些不那么密集的东西。

【问题讨论】:

    标签: android memory bitmap recycle


    【解决方案1】:

    位图内存在本机堆中分配,因此 System.gc() 无济于事。本机堆有自己的 GC,但显然它的启动速度对您来说不够快 - 而且我不知道有任何方法可以强制它(即没有 System.gc() 的本机类似物)。

    您可以按照 Nicklas A 的建议更改应用程序的结构以重用您的位图。

    或者您可以使用BitmapFactory OOM driving me nuts 中详述的本机堆监控机制来确定何时可以安全地分配新位图。

    【讨论】:

    • 啊——所以 System.gc() 的工作原理可能与 wait(200) 完全相同(即它们触发延迟)。我提到了为什么我不能避免大量创建新的位图,尽管我有一些想法可以降低它的频率;文章中的方法正是我想要的。谢谢!
    • 我已经编辑了标题以反映解决方案的特定位图。谢谢!
    【解决方案2】:

    尝试运行System.gc() 而不是睡眠。


    实际上我不确定这是否会有所帮助,因为位图似乎主要是本机代码,这意味着它应该在调用 recycle 后立即释放。


    在我看来,在每个 UI 事件上创建一个新位图似乎是个坏主意,难道你不能只创建一个位图并编辑它吗?

    【讨论】:

    • System.gc() 似乎有效。但是我们不能编辑位图:问题是我们的源位图非常大(大约 2000×3000),因此首先需要使用 BitmapRegionDecoder。可能有一个折中的解决方案(比我们需要的稍大的位图可以减少小平移/缩放的重新加载)。
    • 我建议尽量不要太频繁地创建位图,因为这是一项繁重的操作,尤其是与 UI 相关的时候。
    • 相信我,我不想。我已经编辑了标题,因为答案与位图有关,而不是一般记忆。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多