1

ファイルからデータを読み込むアプリを作成しています。ファイルは比較的大きく(1.8 MB)、onCreateの非同期スレッドから読み取られています。アプリを初めて起動したときは、問題なく読み込まれます。ただし、戻るボタンをクリックしてから再度ロードすると、メモリが不足してクラッシュします(OutOfMemoryエラーが発生します)。

可能な限り最小量のメモリを使用したり、実行時にそのメモリを解放したりするにはどうすればよいですか?

ファイル読み取りコード(doInBackground()非同期クラスのメソッドで実行):

public ArrayList<String> createDataList() {
    dataList = new ArrayList<String>();
    BufferedReader br = null;
    try {
        br = new BufferedReader(new InputStreamReader(getAssets().open(
                    "text.txt")));
        String data;
        while ((data = br.readLine()) != null) {
            dataList.add(data);
        }                           
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            br.close(); // stop reading
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    return dataList;
}

編集*非同期クラス:

private class loadData extends AsyncTask<Void, Void, ArrayList<String>> {

    @Override
    protected ArrayList<String> doInBackground(Void... arg0) {
        dataList = createDataList();
        return dataList;
    }

    protected void onPostExecute(ArrayList<String> result) {
        super.onPostExecute(result);
        // display first element in ArrayList in TextView as a test

    }

}

データを整理し、各テキストファイルのデータを個別に保存する方法に基づいてファイルを分割しようとしましたが、ArrayListメモリの問題もありました。また、すべてのデータを1つの「マスター」に保存し、ArrayListその「マスター」でメソッドを呼び出して、データを適切なものに追加しましたArrayList(コピーしたらすぐに「マスター」からデータを削除/クリアします)。

メモリへの影響を合理化および削減する方法についてのアイデアはありますか?

編集**

Logcat:

ここに画像の説明を入力してください

これは、戻るボタンをクリックしてからアクティビティを再度ロードしたときからです。以下は、(詳細に)生成されるメッセージの1つにすぎません。

ここに画像の説明を入力してください

4

3 に答える 3

1

マニフェストに追加android:largeHeap="true"してみることができますが、Android API-8 ではサポートされていません。私の理解では、データを読み取ってヒープメモリに保存していますが、これは通常非常に限られており、そのサイズはアプリを実行しているデバイスによって異なります。

ここでも調査することをお勧めします: Android - メモリ不足

于 2013-02-08T00:35:15.730 に答える
0

文字列の不変性に少し問題があるようです。

たとえばStringBuilderを使用するように、コードを変更してみませんか?もちろん、複数の変更を加える必要がありますが、コードと十分に類似しており、メモリがすぐにいっぱいになることはありません。

于 2013-02-08T02:59:15.927 に答える
0

まず、メモリ内にデータのコピーが 2 つないことを確認します。新しい ArrayList の作成を開始する前に、古い ArrayList への参照を null にすることができますが、これは慎重に行う必要がありますArrayList.clear()。最初に呼び出した方が完全です。

hprof次に、 Eclipse MATなどのツールを使用して、ArrayList が消費しているメモリの量を把握します。大量のスペースを使用している場合は、よりコンパクトなデータ表現を検討することをお勧めします。

コード スニペットを見ると、バイトから文字への変換を使用して、ファイルから多数のテキスト文字列を読み取っているように見えます。ソース マテリアルがプレーンな UTF-8 (つまり、本質的に ASCII) の場合、UTF-16 への 2 倍の拡張と、それを保持するための char[] オブジェクトの割り当て、さらにそれをラップする String オブジェクトのサイズが必要です。加えて、ArrayList 内のエントリのオーバーヘッド。ファイル内の平均的な文字列の長さに応じて、これは 1.8MB のかなりの倍数になる可能性があります。

これを回避する 1 つの方法は、ファイルを としてメモリに読み込み、byte[]それをスキャンして各文字列の開始位置を特定し、各文字列の開始オフセットを含む整数の配列を保持することです。文字列 N が必要な場合は、 からbyte[]aにデコードしてString返します。これにより、オーバーヘッドが大幅に削減されます。ファイルをロードせず、必要に応じて個々の文字列を読み取るだけで(を使用して)さらに削減できますが、これによりRandomAccessFile速度が低下する可能性があります。

于 2013-02-08T02:04:47.357 に答える