1

多数の画像に非常に迅速にアクセスする必要があるアプリがあるため、これらの画像を何らかの方法でメモリにロードする必要があります。ビットマップが 100 MB を超える RAM を使用するため、これはまったく問題外でした。そのため、jpg ファイルをメモリに読み込み、byteArray 内に格納することにしました。次に、それらをデコードし、必要に応じてキャンバスに書き込みます。これは非常にうまく機能し、メモリ制限を尊重しながら、遅いディスク アクセスを排除します。

ただし、メモリ使用量は「オフ」のようです。それぞれ約 33kb のファイル サイズで 450 の jpg を保存しています。これは合計で約 15MB のデータです。ただし、Eclipse DDMS と Android (物理デバイス上) の両方で報告されているように、アプリは 35MB から 40MB の RAM で継続的に実行されます。読み込まれる jpg の数を変更してみましたが、アプリが使用する RAM は jpg あたり約 60 ~ 70kb 減少する傾向があり、各画像が RAM に 2 回保存されることを示しています。メモリ使用量は変動しません。これは、実際の「リーク」が関係していないことを意味します。

関連する読み込みコードは次のとおりです。

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 に jpg を格納するのに、それだけのオーバーヘッドが関係しているのでしょうか?

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

これは、バイト配列が 2 次元であり、バイト配列を使用してイメージをロードするために必要な次元が 1 つだけであり、2 番目の次元が必要な Ram を 2 倍にする可能性があるためである可能性があります。使用しないでください

于 2013-08-09T17:44:47.683 に答える