【问题标题】:Bitmap size exceeds VM budget, not understanding why位图大小超出 VM 预算,不明白为什么
【发布时间】:2011-09-14 07:43:49
【问题描述】:

我到处寻找“位图大小超出 VM 预算”的问题,但似乎没有一个解决方案适合我。我不明白为什么我的程序有时会抛出此错误,因为我使用它的方式似乎不会导致任何可能的内存泄漏。我的堆栈跟踪指向 BitmapFactory.decodeResource() 方法。我有一个背景图像,我用它在画布上绘制,这就是我初始化它的方式:

Bitmap backgroundImage = BitmapFactory.decodeResource(getResources(),
    R.drawable.background);
backgroundImage = resizeImage(backgroundImage, w, h);

这就是我一直在使用它的方式:

canvas.drawBitmap(backgroundImage, 0, 0, paint);

我认为将backgroundImage = null 放在 onDestroy 方法中会有所帮助,但这并没有起到任何作用。除了 XML 文件外,我的程序中没有其他对背景图像资源的引用,但我认为这不会影响它。有人可以向我解释为什么会发生这种情况以及如何解决吗?

顺便说一句,这个应用程序不涉及屏幕方向更改。

【问题讨论】:

  • 你有一个字段和一个名为backgroundImage的局部变量吗?您可以在 Eclipse 中轻松检查这一点,方法是转到 Window > Preferences,然后导航到 Java > Compiler > Errors/Warnings 并将“Local variable declarations hides another field or variable”设置为 Warning。
  • 不,类中只有一个 backgroundImage,它是一个私有类变量。
  • 只是这段代码:Bitmap backgroundImage = BitmapFactory.... 看起来像是一个局部变量声明。
  • 您多久调用一次此代码?您可能会因为一遍又一遍地将相同的图像加载到内存中而耗尽内存,而 GC 无法跟上。如果您调用它的频率足够高并且图像永远不会改变.. 考虑将 backgroundImage 设为一个字段。
  • 对不起,我让它看起来像一个局部变量只是为了显示类型;但在实际程序中,它是一个类变量。我不认为这会影响它,不是吗?

标签: android memory bitmap memory-leaks


【解决方案1】:

完成后,您需要释放位图像素。你提到你将它的值设置为null,但这只会使它符合 GC,它没有明确告诉VM你已经完成了这些像素,现在这很好是时候释放他们了。

在将其设置为 null 之前,只需在 Bitmap 上调用 Bitmap#recycle()

protected void onDestroy() {
    if (this.backgroundImage != null) {
        this.backgroundImage.recycle();
        this.backgroundImage = null;
    }
}

此外,您可能在 resizeImage() 方法中浪费资源,而您没有提供代码。在解码时对位图进行适当的下采样效率更高,而不是加载全尺寸的位图,然后从那里按比例缩小。

一般技术是使用 BitmapFactory.decodeResource() 的 3-argument versionBitmapFactory.Options#inJustDecodeBounds 进行首次传递,以获得位图的宽度/高度(尽管在您的情况下,因为它来自应用程序的资源,没有理由你甚至应该这样做..但无论如何我会解释它);然后根据目标大小确定合适的samplesize,并再次解码位图。这通常会导致更少的内存使用,尤其是对于非常大的图像(例如,将inSampleSize 设置为 2,它会解码全尺寸位图,但只为原始大小一半的位图分配足够的内存,缩小位图过程中)。

【讨论】:

  • 参见groups.google.com/group/android-developers/browse_thread/thread/… 以获得其他解释和示例代码。另外,需要注意的另一件事是:确保您只在 Activity 的单个实例中解码位图 一次(例如,在 Activity#onCreate() 中进行解码,而不是在其他获得多次调用)
  • 我看过几个例子,但我不明白我应该做什么。那么我将编写什么代码来解码位图资源并使用尺寸(例如 480x800)接收它?
  • 好问题:看看 Gallery 应用程序中的一些代码,它计算用于“inSampleSize”的适当样本大小:android.git.kernel.org/?p=platform/packages/apps/… 查看 computeInitialSampleSize() 和 computeSampleSize()。你可以这样称呼它:Util.computeSampleSize(options, 480, 480*800); 这意味着“最小的边应该至少为 480 像素”和“缩小它直到它适合 480x800”。在第 1 次和第 2 次解码通道之间执行此操作。
  • xml资源中加载的图片背景呢?
猜你喜欢
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 2011-04-26
  • 2011-08-23
  • 1970-01-01
相关资源
最近更新 更多