1

我有一个应用程序需要非常快速地访问大量图像,因此我需要以某种方式将这些图像加载到内存中。这样做是因为位图使用了超过 100MB 的 RAM,这完全不可能,所以我选择将 jpg 文件读入内存,将它们存储在 byteArray 中。然后我将它们解码并根据需要将它们写入画布。这工作得很好,减少了缓慢的磁盘访问,同时也尊重内存限制。

但是,内存使用对我来说似乎“关闭”。我存储了 450 个 jpg,每个文件大小约为 33kb。总共大约 15MB 的数据。但是,正如 Eclipse DDMS 和 Android(在物理设备上)报告的那样,该应用程序持续在 35MB 到 40MB 的 RAM 上运行。我尝试修改加载的 jpg 数量,并且应用程序使用的 RAM 每张 jpg 会减少大约 60-70kb,这表明每个图像在 RAM 中存储了两次。内存使用量没有波动,这意味着没有涉及实际的“泄漏”。

这是相关的加载代码:

private byte[][] bitmapArray = new byte[totalFrames][];
for (int x=0; x<totalFrames; x++) {
    File file = null;
    if (cWidth <= cHeight){
            file = new File(directory + "/f"+x+".jpg");
    } else {
            file = new File(directory + "/f"+x+"-land.jpg");
    }
    bitmapArray[x] = getBytesFromFile(file);
    imagesLoaded = x + 1;
}


public byte[] getBytesFromFile(File file) {
    byte[] bytes = null;
    try {

        InputStream is = new FileInputStream(file);
        long length = file.length();

        bytes = new byte[(int) length];

        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
            offset += numRead;
        }

        if (offset < bytes.length) {
            throw new IOException("Could not completely read file " + file.getName());
        }

        is.close();
    } catch (IOException e) {
                  //TODO Write your catch method here
    }
    return bytes;
}

最终,它们会像这样被写入屏幕:

SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
    c = holder.lockCanvas();
    if (c != null) {            
        int canvasWidth = c.getWidth();
        int canvasHeight = c.getHeight();
        Rect destinationRect = new Rect();
        destinationRect.set(0, 0, canvasWidth, canvasHeight);
        c.drawBitmap(BitmapFactory.decodeByteArray(bitmapArray[bgcycle], 0, bitmapArray[bgcycle].length), null, destinationRect, null);
    }
} finally {
    if (c != null)
    holder.unlockCanvasAndPost(c);
}

我是否正确,这里发生了某种重复?或者像这样在 byteArray 中存储 jpgs 是否有那么多开销?

4

2 回答 2

1

在 RAM 中存储字节与在硬盘驱动器上存储数据非常不同......它的开销要大得多。对对象的引用以及字节数组结构都占用了额外的内存。所有额外内存并没有真正的单一来源,但请记住,将文件加载到 RAM 通常会占用 2 ~ 3 倍的空间(根据经验,恐怕我不能在这里引用任何文档)。

考虑一下:

File F = //Some file here (Less than 2 GB please)
FileInputStream fIn = new FileInputStream(F);
ByteArrayOutputStream bOut = new ByteArrayOutputStream(((int)F.length()) + 1);

int r;
byte[] buf = new byte[32 * 1000];

while((r = fIn.read(buf) != -1){
    bOut.write(buf, 0, r);
}

//Do a memory measurement at this point. You'll see your using nearly 3x the memory in RAM compared to the file.
//If your actually gonna try this, remember to surround with try-catch and close the streams as appropriate.

还要记住,未使用的内存不会立即清除。getBytesFromFile() 方法可能会返回字节数组的副本,这会导致内存重复,可能不会立即被垃圾收集。如果您想安全起见,请检查 getBytesFromFile(file) 方法没有泄漏任何应该清理的引用。它不会显示为内存泄漏,因为您只调用它有限次。

于 2013-08-09T18:01:23.293 回答
0

这可能是因为您的字节数组是二维的,您只需要一维来使用字节数组加载图像,而第二维可能会使所需的 Ram 翻倍,因为对于每个字节,您将有一个空但仍然存在的字节不要使用

于 2013-08-09T17:44:47.683 回答