How to fix a "java.lang.OutOfMemoryError: bitmap size exceeds VM budget " error on android
I've seen this question asked many times but none of the answers really made sense in what I'm doing... I have an android game (see source at google source control) It's a card game, and I've used a method that redraws each hand every round - that might be wasteful but I couldnt think of a better way to do it. Here is the code for the redrawHand method:
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(); }
After installing ACRA (http://code.google.com/p/acra/wiki/ACRAHowTo) I have started getting crash reports from devices claiming saying the following:
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) 开发者_如何学JAVA 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)
I am not able to understand why this is happening - is there a memory leak? should I somehow release something that I'm missing? Please help, there are a lot of people that can't enjoy this free open source game because of this. Thanks!
From the stack trace you can see a bitmap is being allocated as a side-effect of the setImageResource() call in redrawHand.
Generally, bitmaps and resources like this should be allocated once, at startup, and not on every redraw. If you load your image resources in onCreate (or onResume?) and then reference those during redraw I think you'll avoid the bug.
I'm not entirely clear on why this is manifesting as a memory leak though. Technically, if you allocate new bitmap memory to back a View, the old memory should get released. Perhaps the GC is falling behind on some systems and can't keep up with the rate at which you're allocating new bitmaps?
精彩评论