在byteArray中存储图像时的内存问题

时间:2013-08-09 17:12:25

标签: java android performance

我有一个应用程序需要非常快速地访问大量图像,所以我需要以某种方式将这些图像加载到内存中。这样做的位图使用超过100MB的RAM,这是完全不可能的,所以我选择将jpg文件读入内存,将它们存储在byteArray中。然后我解码它们并在需要时将它们写入画布。这非常有效,可以减少磁盘访问速度,同时还可以考虑内存限制。

然而,内存使用对我来说似乎“关闭”。我正在存储450个jpgs,每个文件大小约为33kb。这总计约15MB的数据。但是,Eclipse DDMS和Android(在物理设备上)报告的应用程序持续运行在35MB到40MB之间的RAM。我已经尝试修改加载了多少jpgs,并且应用程序使用的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会有多少开销?

2 个答案:

答案 0 :(得分: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)是否泄漏了应该清理的任何引用。它不会出现内存泄漏,因为您只能将其称为有限次数。

答案 1 :(得分:0)

这可能是因为你的字节数组是2维的,你只需要一个维度来使用字节数组加载图像,而第二个维度可能会使所需的Ram​​加倍,因为每个字节都是空的但仍然存在你不使用的字节