【问题标题】:Android: Memory friendly modification of image bytesAndroid:图像字节的内存友好修改
【发布时间】:2013-06-20 15:24:49
【问题描述】:

我目前正在制作一个修改图像的某些字节的 Android 应用程序。为此,我编写了以下代码:

Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(path));
ByteBuffer buffer = ByteBuffer.allocate(bmp.getWidth()*bmp.getHeight());
bmp.copyPixelsToBuffer(buffer);
return buffer.array();

问题是这种方式使用了太多的堆内存,并抛出OutOfMemoryException。 我知道我可以让应用程序的堆内存更大,但这似乎不是一个好的设计选择。

有没有更节省内存的方式来改变图像的字节数?

【问题讨论】:

  • 在这种情况下增加堆实际上可能不是一个糟糕的设计选择。图像编辑器尤其需要比常规应用程序更多的堆内存。事实上,这是推荐使用更大堆大小的一个示例(查看关于内存管理的 Google I/O 讲座——我认为它来自 2011 年)。
  • bufferByteBuffer?
  • @fge 是的,我会把它添加到帖子中。
  • @Rarw 我将观看 Google I/O 讲座。感谢您的提示!
  • 也许您可以使用内存映射文件而不是在堆上分配的缓冲区?

标签: java android bitmap bitmapfactory


【解决方案1】:

托管堆上似乎有两个像素数据副本:

  • Bitmap 中的未压缩数据
  • ByteBuffer中的数据副本

通过将数据保留在位图中并使用getPixel() / setPixel()(或者可能使用“批量”变体一次编辑一行)可以将内存需求减半,但这会增加一些开销。

根据图像的性质,您可以使用不太精确的格式(例如 RGB 565 而不是 8888),从而将内存需求减半。

正如其中一个 cmets 所述,您可以将数据解压缩到文件中,使用 java.nio.channels.FileChannel#map() 对其进行内存映射,然后通过 MappedByteBuffer 访问它。这会增加加载和保存的开销,并且可能很烦人,因为您必须通过 ByteBuffer 而不是 byte[] 工作。

另一种选择是使用android:largeHeap (documented here) 扩展堆,尽管在某些方面您只是推迟了不可避免的事情:您可能会被要求编辑对于“大”堆来说太大的图像。此外,“大”堆的容量因设备而异,就像“正常大小”的堆一样。这是否有意义部分取决于您加载的图像有多大。

在您执行任何此操作之前,我建议您使用堆分析工具(参见例如this blog post)来查看您的内存去向。另外,看一下内存不足异常上面的logcat;它应该确定失败的分配的大小。确保它看起来“合理”,即您不会无意中分配比您认为的更多的钱。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    • 1970-01-01
    • 2014-04-08
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    相关资源
    最近更新 更多