Why this image-switching code has memory leak?

2019-07-24 13:03发布

I'm write a simple android application, which uses an ImageView to display an image. When click on a button, it will generate a new bitmap based on current image, and replace the old one.

The image I used is not big: 220 x 213.

But in the emulator, when I click the button the 5th time, it will throw an error:

 java.lang.OutOfMemoryError: bitmap size exceeds VM budget

I've read some articles:

  1. java.lang.OutOfMemoryError: bitmap size exceeds VM budget - Android
  2. http://androidactivity.wordpress.com/2011/09/24/solution-for-outofmemoryerror-bitmap-size-exceeds-vm-budget/
  3. http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html

But still not fix my problem.

My code is:

public class MyActivity extends Activity {
    private Bitmap image;
    private ImageView imageView;
    private Button button;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        this.button = (Button) findViewById(R.id.button);
        this.imageView = (ImageView) findViewById(R.id.image);


        this.image = BitmapFactory.decodeResource(getResources(), R.drawable.m0);
        this.imageView.setImageBitmap(image);

        this.button.setOnClickListener(new View.OnClickListener() {
            private int current = 0;

            @Override
            public void onClick(View view) {
                Bitmap toRemove = image;
                Matrix matrix = new Matrix();
                matrix.setRotate(30, 0.5f, 0.5f);
                image = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true);
                imageView.setImageBitmap(image);

                if (toRemove != null) {
                    toRemove.recycle();
                }
            }
        });
    }
}

You can see I've invoked toRemove.recycle() on the removing image. But it seems no effect.


UPDATE:

Since the error only occurred when I click the button the 5th time(not the first time), we can see the image size is not a problem. And in my code, I tried to release the old image after generating a new one, so I think the old image has not been released proper.

I have invoked toRemove.recycle(), is it the correct method to release an image? Or do I shall use something else?


FINALLY:

Emile is right. I added some code to log the size, and you can see it increasing each time:

08-28 13:49:21.162: INFO/image size before(2238): 330 x 320
08-28 13:49:21.232: INFO/image size after(2238): 446 x 442
08-28 13:49:31.732: INFO/image size before(2238): 446 x 442
08-28 13:49:31.832: INFO/image size after(2238): 607 x 606
08-28 13:49:34.622: INFO/image size before(2238): 607 x 606
08-28 13:49:34.772: INFO/image size after(2238): 829 x 828
08-28 13:49:37.153: INFO/image size before(2238): 829 x 828
08-28 13:49:37.393: INFO/image size after(2238): 1132 x 1132

1条回答
趁早两清
2楼-- · 2019-07-24 13:08

I'm not sure quite how Bitmap.createBitmap() works, but given the error is to do with the 'bitmap size'

java.lang.OutOfMemoryError: bitmap size exceeds VM budget

I would presume that the image is increasing in size with each click. Hence the error occurring on the 5th click.

I would suggest that the size increase is to do with the rotation matrix. When the image is rotated it appears that it isn't cropping the rotated image to the image width and height, but rather increasing the size of the image.

You would have to try some alternative methods for manipulating the rotation within the w/h bounds you desire.

An answer (two down) to this question shows how to crop the rotated image if you so wished. Android: How to rotate a bitmap on a center point

RectF rectF = new RectF(0, 0, source.getWidth(), source.getHeight());
matrix.mapRect(rectF);
查看更多
登录 后发表回答