如何在安卓设备上修复“java.lang.OutOfMemoryError: bitmap size exceeds VM budget”错误

3
我看到这个问题已经被问了很多次,但是没有一个答案真正能够解释我正在做的事情... 我有一个安卓游戏(源代码在谷歌源代码控制中可见) 这是一款纸牌游戏,我使用了一种方法,每轮重新绘制每一手牌 - 这可能是浪费的,但我想不出更好的方法。 这是redrawHand方法的代码:
private void redrawHand(Hand hand) {
  ImageView[] cardView = hand.getCardsViews();
  View container = hand.getContainer();
  for (int i = 0; i < GameData.YANIV_NUM_CARDS; i++) {
   PlayingCard card = hand.getCardByLocation(i);
   if (card != null) {
    // Show Card
    cardView[i].setVisibility(View.VISIBLE);
    int resId;
    if (hand.shouldCardsBeShown()) {
     resId = card.getImageResourceId();
    } else {
     resId = R.drawable.back;
    }
    cardView[i].setImageResource(resId);
// TODO: Disgusting patch, need to fix asap!!!
if (hand.isHumanPlayer()) {
 // Show isSelected
 // when selected, move up 15 pixels
 boolean isSelected = hand.isCardSelected(i);
 ((LinearLayout.LayoutParams) cardView[i].getLayoutParams()).bottomMargin = isSelected? 15 : 0;
}   } else {
cardView[i].setVisibility(View.INVISIBLE);   }  }  // Set player name hand.getHandLabelView().setText(hand.getHandLabel());  container.requestLayout(); }

安装了ACRA后(http://code.google.com/p/acra/wiki/ACRAHowTo),我开始从设备上收到崩溃报告,报告称以下错误:
java.lang.OutOfMemoryError: bitmap size exceeds VM budget at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:363) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:212) at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:673) at android.content.res.Resources.loadDrawable(Resources.java:1639) at android.content.res.Resources.getDrawable(Resources.java:535) at android.widget.ImageView.resolveUri(ImageView.java:541) at android.widget.ImageView.setImageResource(ImageView.java:293) at com.geekadoo.ui.Yaniv.redrawHand(Yaniv.java:765) at com.geekadoo.ui.Yaniv.performYaniv(Yaniv.java:539) at com.geekadoo.ui.Yaniv.performYanivHandler(Yaniv.java:503) at com.geekadoo.ui.Yaniv.access$1(Yaniv.java:502) at com.geekadoo.ui.Yaniv$2.onClick(Yaniv.java:323) at android.view.View.performClick(View.java:2196) at android.view.View.onTouchEvent(View.java:3849) at android.widget.TextView.onTouchEvent(TextView.java:6376) at android.view.View.dispatchTouchEvent(View.java:3385) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:872) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:872) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:872) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:872) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:872) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:872) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:872) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:872) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1764) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1213) at android.app.Activity.dispatchTouchEvent(Activity.java:2066) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1748) at android.view.ViewRoot.handleMessage(ViewRoot.java:1561) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:123) at android.app.ActivityThread.main(ActivityThread.java:3977) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:521) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540) at dalvik.system.NativeStart.main(Native Method)

我无法理解为什么会出现这种情况 - 是否存在内存泄漏?我是否应该释放一些我遗漏的东西? 请帮忙,有很多人因为这个问题无法享受这个免费开源游戏。 谢谢!


当我在MapView上快速缩放时,我一直遇到这个问题。我看到了Romain Guy(Google工程师)的答案,他基本上说你使用了太多的内存,要解决这个问题,你只需要使用更少的内存。你分配了太多大的位图,因此会出现错误。虽然不是很具体,但这可能就是问题所在。如果您编辑您的帖子并正确格式化它,我将深入阅读您的代码。 - Austyn Mahoney
正如您在我的Google Code上的代码中所看到的,我没有使用大位图,我怀疑存在内存泄漏,但无法弄清楚为什么会发生... - ekatz
1个回答

0

从堆栈跟踪中,您可以看到在redrawHand中的setImageResource()调用的副作用是分配了位图。

通常,像这样的位图和资源应该在启动时分配一次,而不是在每次重绘时分配。如果您在onCreate(或onResume?)中加载图像资源,然后在重绘期间引用它们,我认为您将避免出现错误。

但我并不完全清楚为什么会出现内存泄漏。从技术上讲,如果您分配新的位图内存来支持视图,则旧内存应该被释放。也许在某些系统上GC落后于您分配新位图的速度,无法跟上?


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