【问题标题】:Android Out Of Memory Exception storing huge amount of bytesAndroid Out Of Memory Exception 存储大量字节
【发布时间】:2016-02-22 20:43:54
【问题描述】:

我正在开发 android 中的绘画应用程序。 目前我正在研究撤消功能 - 我的想法是存储更改的像素的坐标和颜色。

我正在使用 RGB 来解决性能问题 - 所以它们存储在一个字节数组中。

currentRGBPixelArray 是包含旧 ARGB 值的数组。 updatedRGBPixelArray 是包含新 ARGB 值的数组。

如果总是 3 个字段中的值不同,我知道我必须存储这些值。这是在 Integer, Byte[] 对上完成的,其中 Integer 是 RGBPixelArray 中像素的索引。

但是使用这段代码时,我在存储大量数据时会出现内存不足异常(例如,如果背景或像 1920*1080 的屏幕这样的大区域被更改,可能会更改多次)。

这是我的代码:

List<Pair<Integer, Byte[]>> changeTupelHolder = new ArrayList<>();
for (int index = 0; index < width; index += 4) 
{
     if (currentRGBPixelArray[index] != updatedRGBPixelArray[index] ||
         currentRGBPixelArray[index+1] != updatedRGBPixelArray[index+1] ||
         currentRGBPixelArray[index+2] != updatedRGBPixelArray[index+2]) 
     {
           Pair<Integer, Byte[]> changeTupel = 
               new Pair<>(index, 
                          new Byte[]{currentRGBPixelArray[index],
                                     currentRGBPixelArray[index+1],
                                     currentRGBPixelArray[index+2]});
           changeTupelHolder.add(changeTupel);
     }
}

然后 changeTupelHolder 再次存储在 Stack 中,并在调用 undo 时弹出。

如何处理内存不足异常? 将 changeTupelHolder 存储在存储上是个好主意(性能?)? 如果是,当应用程序趋于内存不足时,我该怎么做?

或者你对我的问题有完全不同的想法?

感谢您的帮助!

【问题讨论】:

  • 您能否详细解释一下您应该在什么时候存储更改?什么情况下会触发你的代码?另外,你可以使用 SVG 之类的东西吗?
  • 这只是一个简单的绘画活动——如果我画一个圆,填充一个区域或任何我想存储旧像素的东西。
  • 如果它只是一个简单的绘画活动,那么您应该能够使用向量并将它们作为路径存储在您的堆栈中。

标签: java android out-of-memory bytearray


【解决方案1】:

这是一种非常低效的保存图像数据的方法。保存图像数据的正确方法是字节数组 byte data[]=new byte[4*NUM_PIXELS]。然后获取像素的颜色将是 data[pixelnum*4+COLOR_INDEX] 其中颜色索引为 0 表示 alpha,1 表示红色,2 表示绿色,3 表示蓝色。

您的操作方式 - 您正在创建数以百万计的小对象,每个小对象都有自己的大量开销,每个对象都存储一个字节。这会杀死一台PC。而手机在分配方面可怕,高性能的 android 代码的关键是尽量减少分配的对象数量。

我知道现代的思想流派是在你知道存在问题之前不要考虑性能,但是有一个巨大的星号 - 你仍然需要使用常识。常识应该告诉你,每像素 1 个对象是个坏主意。

【讨论】:

  • 我不确定你说得对不对。我将图像存储在 currentRGBPixelArray 中,它是字节 [4*NUM_PIXELS],updatedRGBPixelArray 只是临时的,只是更改存储为对,因为在大多数情况下,2.000.000 个像素中可能只有 2.000 个被更改,例如,如果你只是画一个圆圈或一条线。
  • 分配甚至 2000 个对象 - 不计算列表将在内部分配的较小对象 - 是一个巨大的数量,永远不应该这样做。
【解决方案2】:

我会用向量来做这件事。

实际上,我已经使用向量进行了类似于撤消/重做的操作,并且从未遇到过内存不足异常。

我使用android.graphics.Pathandroid.graphics.Paint 创建了一个矢量对象。

以下是将 SVG 转换为路径和绘制的示例代码:

public VectorPathObject(final List<List<Object>> actions, final float left, final float top, final String color, final float strokeWidth) {
    mPath = new Path();
    for (List<Object> action : actions) {
        switch (action.get(0).toString()) {
            case M:
                mPath.moveTo(left + Float.parseFloat(action.get(1).toString()), top + Float.parseFloat(action.get(2).toString()));
                break;
            case Q:
                mPath.quadTo(left + Float.parseFloat(action.get(1).toString()), top + Float.parseFloat(action.get(2).toString()), left + Float.parseFloat(action.get(3).toString()), top + Float.parseFloat(action.get(4).toString()));
                break;
            case L:
                mPath.lineTo(left + Float.parseFloat(action.get(1).toString()), top + Float.parseFloat(action.get(2).toString()));
                break;
        }
    }
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setStyle(this.paintStyle);
    mPaint.setStrokeCap(this.lineCap);
    mPaint.setStrokeJoin(Paint.Join.MITER);
    mPaint.setColor(Color.parseColor(color));
    mPaint.setStrokeWidth(strokeWidth);
    mPaint.setAlpha(this.opacity);
}

【讨论】:

  • 这看起来不错,但我确实有一个填充工具,可以填充所有类型的表格,我无法想象用这种方法处理这个问题的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-25
  • 1970-01-01
相关资源
最近更新 更多