在Android应用程序上创建Bitmaps时的OOM

时间:2015-03-05 08:47:27

标签: android out-of-memory android-bitmap

我有一个应用程序从相机预览中获取固定数量的图像,并将它们转换为Bitmaps列表。为此,我有以下代码:

private Camera.PreviewCallback SetPreviewCallBack() {
    return new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
    List<Bitmap> imageList = new ArrayList<Bitmap>();
    for (int i=0; i<30; i++) // Let's suppose this is the real loop. 
                             // It's not, as the real loop takes each camera preview frame, 
                             // instead of inserting the same one 30 times. 
                             // But for this example, it's OK
    {
        imageList.add(GetBitmap(
                    data, 
                    previewWidth, // Calculated
                    previewHeight, // Calculated 
                    previewFormat, // Calculated
                    previewRotation)); // Calculated
    }

}

private Bitmap GetBitmap(byte[] data, int width, int height, int previewFormat, int rotation) { 

    YuvImage yuv = new YuvImage(data, previewFormat, width, height, null);

    ByteArrayOutputStream out = new ByteArrayOutputStream();
    yuv.compressToJpeg(new Rect(0, 0, width, height), 50, out);

    byte[] bytes = out.toByteArray();
    final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

    Bitmap imageResult = RotateImage(bitmap, 4 - rotation);
    bitmap.recycle();

    return imageResult;
} 

private Bitmap RotateImage(Bitmap rotateImage, int rotation) {

    Matrix matrix = new Matrix();
    switch (rotation) {
    case 1:
        matrix.postRotate(270);
        break;
    case 2:
        matrix.postRotate(180);
        break;
    case 3:
        matrix.postRotate(90);
        break;
    }

    return Bitmap.createBitmap(rotateImage, 0, 0, rotateImage.getWidth(),
            rotateImage.getHeight(), matrix, true);
}

我的工作是:      - 我将此图片存储在Singleton课程中,以便从同一应用程序中的另一个Activity访问该图片。      - 我再次调用这段代码(当某些事件发生时)并重复图像提取/保存过程。

03-05 09:35:13.339: E/AndroidRuntime(8762): FATAL EXCEPTION: Thread-818
03-05 09:35:13.339: E/AndroidRuntime(8762): java.lang.OutOfMemoryError
03-05 09:35:13.339: E/AndroidRuntime(8762):     at android.graphics.Bitmap.nativeCreate(Native Method)
03-05 09:35:13.339: E/AndroidRuntime(8762):     at android.graphics.Bitmap.createBitmap(Bitmap.java:726)
03-05 09:35:13.339: E/AndroidRuntime(8762):     at android.graphics.Bitmap.createBitmap(Bitmap.java:703)
03-05 09:35:13.339: E/AndroidRuntime(8762):     at android.graphics.Bitmap.createBitmap(Bitmap.java:636)
03-05 09:35:13.339: E/AndroidRuntime(8762):     at com.facephi.sdk.ui.CameraPreview.RotateImage(CameraPreview.java:779)
03-05 09:35:13.339: E/AndroidRuntime(8762):     at com.facephi.sdk.ui.CameraPreview.GetBitmap(CameraPreview.java:712)

我尝试使用最佳做法以正确的方式删除未发布的Bitmaps已发布的here,但没有运气......

我为什么会遇到这个OOM错误?

2 个答案:

答案 0 :(得分:2)

Android中的内存非常有限,这就是您获得此异常的原因。一般来说,你不应该在内存中存储这么多图像,只应在需要时加载它们(即显示它们或用它们做某事)并且应该尽快处理它们(recycle())因为你已经完成了它们。此外,您只应以尽可能低的分辨率加载它们。

说完所有这些,并且不知道为什么你必须将它们都放在内存中(你可能有正当理由),你可以通过在清单中指定适当的属性来增加应用程序的堆大小({{ 3}})但即使这并不能保证你可以加载太多图像。

请记住,默认情况下,Android会为您的图像使用每像素4个字节,因此如果您有30张图像,每张图像的像素密度为100万,那么您将使用1.2亿字节或大约120MB的内存。相比之下,应用程序的默认分配字节可以低至16mb(取决于许多情况。请参阅此处了解更多详细信息:http://developer.android.com/guide/topics/manifest/application-element.html#largeHeap)。

如果您可以以某种方式更改代码,以便不必将它们全部加载到内存中,您可以查看位图缓存(Android heap size on different phones/devices and OS versions),这可以极大地帮助您的内存管理问题。

答案 1 :(得分:1)

1。尝试使用

BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 8;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);

这将极大地帮助节省内存。

2。不要&#34;存储&#34;单个或其他任何地方的Bitmap对象。这将始终导致OutOfMemoryError。每次要使用时都重新创建Bitmap

修改

另请参阅官方ThreadSample示例和Displaying Bitmaps Efficiently教程。