【问题标题】:Android - BitmapFactory.decodeByteArray - OutOfMemoryError (OOM)Android - BitmapFactory.decodeByteArray - OutOfMemoryError (OOM)
【发布时间】:2011-11-09 14:24:16
【问题描述】:

我已经阅读了 100 多篇关于 OOM 问题的文章。大多数是关于大位图的。我正在做一个地图应用程序,我们在其中下载256x256 天气叠加图块。大多数都是完全透明的并且非常小。我刚刚在调用 BitmapFactory.decodeByteArray(....). 时遇到了 442 字节长的位图流崩溃

例外状态:

java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=9415KB, Allocated=5192KB, Bitmap Size=23671KB)

代码是:

protected Bitmap retrieveImageData() throws IOException {
    URL url = new URL(imageUrl);
    InputStream in = null;
    OutputStream out = null;
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();

    // determine the image size and allocate a buffer
    int fileSize = connection.getContentLength();
    if (fileSize < 0) {
        return null;
    }
    byte[] imageData = new byte[fileSize];

    // download the file
    //Log.d(LOG_TAG, "fetching image " + imageUrl + " (" + fileSize + ")");
    BufferedInputStream istream = new BufferedInputStream(connection.getInputStream());
    int bytesRead = 0;
    int offset = 0;
    while (bytesRead != -1 && offset < fileSize) {
        bytesRead = istream.read(imageData, offset, fileSize - offset);
        offset += bytesRead;
    }

    // clean up
    istream.close();
    connection.disconnect();
    Bitmap bitmap = null;
    try {
        bitmap = BitmapFactory.decodeByteArray(imageData, 0, bytesRead);
    } catch (OutOfMemoryError e) {
        Log.e("Map", "Tile Loader (241) Out Of Memory Error " + e.getLocalizedMessage());
        System.gc();
    }
    return bitmap;

}

这是我在调试器中看到的:

bytesRead = 442

所以位图数据是 442 字节。为什么它会尝试创建一个 23671KB 的位图并耗尽内存?

【问题讨论】:

  • 需要注意的是,一些OOM不一定是由触发错误的页面引起的。有时,OOM 是由以前的活动/错误的累积触发的,这些活动/错误是由位图操作偶然触发的。我们应该将应用程序视为一个整体,而不仅仅是触发 OOM 的地方。我刚刚回答的一个最近的 SO 问题说明了这种情况 stackoverflow.com/questions/7136198/…,其中 OOM 不一定是由引发错误的 Activity 引起的。
  • SO 上已经有很多与这个问题相关的答案,这是应该适合您的解决方案之一。 Memory exceeds 更新: 另一个不错的答案在这里,Memory Leaks

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


【解决方案1】:

我过去曾遇到过类似的问题。 Android 使用 Bitmap VM,而且非常小。确保通过 bmp.recycle 处理位图。更高版本的 Android 有更多的 Bitmap VM,但我一直在处理的版本有 20MB 的限制。

【讨论】:

  • 我已经尽力做到了。这正在绘制这些小位图中的大约 12-18 个。最大的约为10K。所以我把它做得尽可能瘦。它是 442 字节,正在扩展到 20+MB。这是在 Android 2.3 上
  • 伙计们,这也是一个缓存平铺图像以在 MapView 上绘图的例程。我无法回收位图,否则地图上的绘制例程将崩溃。
【解决方案2】:

这可能有效。将位图缩小到较低质量。我不确定,但这可能会复制内存中的图像,但很容易值得一试。

            Bitmap image;
   image = BitmapFactory.decodeByteArray(data, 0, data.length);
   Bitmap mutableBitmap = image.copy(Bitmap.Config.ARGB_4444, true);
   Canvas canvas = new Canvas(mutableBitmap); 

我认为下面的旧答案不适用于流媒体。

                Options options = new BitmapFactory.Options();
        Options options2 = new BitmapFactory.Options();
        Options options3 = new BitmapFactory.Options();

        options.inPreferredConfig = Bitmap.Config.ARGB_8888;///////includes alpha
        options2.inPreferredConfig = Bitmap.Config.RGB_565 ;///////no alpha
        options3.inPreferredConfig = Bitmap.Config.ARGB_4444 ;/////alpha lesser quality

        image=BitmapFactory.decodeResource(getResources(),R.drawable.imagename,options); 
        image=Bitmap.createScaledBitmap(image, widthx,height, true);  

【讨论】:

【解决方案3】:

听起来你已经阅读了一些关于这个主题的书,所以我将省去标准的“这就是你如何解码位图”cmets..

让我大吃一惊的是,您可能正在保留对旧位图的引用(可能图块已移出屏幕,但您在某个数组中仍有引用,因此它不是垃圾集?)。这在过去让我非常痛苦 - 内存泄漏很难调试。

当我遇到类似问题时,有一个很棒的Google I/O video over here 真的帮助了我。大约一个小时,但希望能在几天后为您节省时间。 它涵盖了以下内容:

  1. 创建堆转储
  2. DDMS 中的堆使用情况
  3. 使用 MAT 比较/分析堆转储

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    相关资源
    最近更新 更多