Android 上有没有办法判断 Bitmap 是否已完全释放?
我正在创建一个调用 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 会说“更多核心可用,但没有适合你”,那就太好了,这样我就可以将我的等待循环称为 B 计划,或者最终尝试一些不太密集的东西。
I am creating a viewer application that calls BitmapRegionDecoder.decodeRegion(Rect, BitmapFactory.Options)
. I am disposing of the bitmap previously got from decodeRegion
before each call:
//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);
I was having problems with the fact that on very quick successive UI events, we were running out of memory. As you can see I have "solved" this with the dirty hack (the thread waits 200ms and gives Android a bit of time to catch up).
I'm not very happy with this, for obvious reasons. Firstly, is my diagnosis (that garbage collection is not finishing before we allocate new memory) correct? Secondly, I tried putting
while(!areaBitmap.isRecycled())
around a counter increment after the recycle()
call and the counter stayed at zero. I see the sense in having isRecycled()
do this but I need something like an isCompletelyRecycled()
method instead. Does Android have anything like this? Thirdly, if I can't get anywhere with this, is there an "available memory" method I can use to tell if my call is going to push us over? I can't find one. It would be nice if Android would say MORE CORE AVAILABLE BUT NONE FOR YOU so I could maybe call my wait loop as a plan B, or eventually try something less intensive instead.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
位图内存是在本机堆中分配的,因此 System.gc() 将无济于事。本机堆有自己的 GC,但显然它对您来说启动得不够快 - 而且我不知道有任何方法可以强制它(即没有 System.gc() 的本机类似物)。
您可以更改应用程序的结构,正如 Nicklas A 建议的那样,重新使用您的位图。
或者,您可以使用 BitmapFactory OOM 让我发疯中详细介绍的本机堆监视机制来确定当可以安全地分配新位图时。
Bitmap memory is allocated in the native heap, so System.gc() will not help. The native heap has its own GC, but clearly it is is not kicking in quickly enough for you - and I am not aware of any way to force it (ie there is not a native analogue of System.gc()).
You could change the structure of your application as Nicklas A suggests to re-use your bitmap.
Or you could use the native heap monitoring mechanisms detailed in BitmapFactory OOM driving me nuts to determine when it is safe to allocate a new bitmap.
尝试运行
System.gc()
< /a> 而不是睡眠。实际上,我不确定这是否有帮助,因为位图似乎主要是本机代码,这意味着它应该在调用回收后立即释放。
对我来说,在每个 UI 事件上创建一个新的位图似乎是一个坏主意,难道您不能只创建一个位图并编辑该位图吗?
Try running
System.gc()
instead of the sleep.Actually I'm unsure if this will help as bitmap seems to be mostly native code meaning that it should be released as soon as recycle is called.
To me it seems like creating a new bitmap on every UI event seems like a bad idea, couldn't you just create one bitmap and edit that one?