厄介な問題が
あります。サーバーから大量の GeoJSON データを取得しています。これは、16MB のヒープでも、アプリを数回起動および停止しても機能します。メモリ消費量は一定であり、それを超えることはありません。しかし、16MB のヒープを超える場合があります。簡単に説明したいと思います:
アプリは使用され、ホーム ボタンで「終了」するため、アプリはバックグラウンドに存在し、まだ破棄されていません。アプリが再開されると、アプリの一部である「コントローラー」が新しい GeoJSON データをチェックします。GeoJSON データの更新がある場合、アプリはそれをダウンロードして処理し、ここから問題が始まります。):
private synchronized String readUrlData(HttpURLConnection urlConnection) throws IOException {
Log.i(TAG, "Start reading data from URL");
urlConnection.setReadTimeout(1000 * 45); //45 sec
Reader reader = new InputStreamReader(urlConnection.getInputStream());
StringBuilder sb = new StringBuilder(1024 * 16);
char[] chars = new char[1024 * 16]; //16k
int len;
while((len = reader.read(chars)) >= 0) {
sb.append(chars, 0, len);
}
reader.close();
Log.i(TAG, "Finished reading data from URL");
return sb.toString();
}
append()またはtoString()で OutOfMemory を取得します。明らかに、以前に何らかの形で使用された場合、アプリはこれにほとんどまたは多くのメモリを必要としません。上記のコードに対して、よりリソースに優しい方法を既に見つけようとしましたが、解決策はありません。繰り返しますが、アプリを新規から開始する場合、問題はありません。そして、私はメモリリークがないことを絶対に確信しています。
- この部分などを MAT で確認したところ、1.6MB を超えることはありませんでした (これが GeoJSON データです)。
- このユース ケースを 24MB のヒープ サイズで連続して数回実行しました。
メモリリークがあれば24MBのヒープで3回目から4回目でクラッシュするところだったのですが、問題なく動きました。
クラッシュを回避する方法を知っています。利用可能な新しい GeoJSON データがあり、アプリを再起動する必要があることをユーザーに知らせる AlertDialog をユーザーに表示できます。しかし、落とし穴があります。アプリケーションがアクティビティのfinish()によって「終了」された場合、アプリケーションはまだメモリに残っているため、再起動すると、メモリの割り当てが解除されないため、クラッシュが再び発生します(少なくとも、ほとんどの場合、それに頼ることはできません)。私はすでにそのSystem.exit(0);を理解しました。終了の代わりに、アプリ全体を強制終了するため、すべてのメモリが解放されるため、新しい GeoJSON データで再起動した後にクラッシュは発生しません。しかし、私はこれが良い解決策ではないことを知っています。私はすでにSystem.gc()を試しました重要な部分ですが、これも機能しません。この問題に対処する方法はありますか? おそらく、使用済みメモリをすべて解放してアプリを再起動するようなものが必要です。
別の解決策として、上記のコードを再設計することもできますが、これでより多くの MB を取得できるとは思いません。
これに対する合理的な解決策が見つからない場合は、ヒープが 16MB のときにSystem.exit(0)を使用して (それを確認する方法があると思います)、アプリを再起動します。