我有一个烦人的问题:
我正在从服务器获取大量 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 的堆大小连续多次执行此用例。
如果发生内存泄漏,它会在第 3 次或第 4 次后以 24MB 堆崩溃,但它运行时没有问题。
我知道如何避免崩溃。我可以向用户显示一个 AlertDialog,告诉他有新的 GeoJSON 数据可用,他需要重新启动应用程序。但是有一个问题!如果应用程序被 Activity 的finish() “终止” ,应用程序仍然保留在内存中,所以当它重新启动时,崩溃再次发生,因为内存永远不会被释放(至少在大多数情况下我不能依赖它)。我已经想通了System.exit(0); 而不是完成会释放所有内存,因为它会杀死整个应用程序,因此在使用新的 GeoJSON 数据重新启动后不会发生崩溃。但我知道这不是一个好的解决方案。我已经尝试过System.gc()在重要部分,但这也不起作用。任何想法如何处理这个问题?可能我需要重新启动应用程序并释放所有已使用的内存。
另一种解决方案可能是重新设计上面的代码,但我认为不可能从中获得更多的 MB。
如果我没有找到合理的解决方案,我将在堆为 16MB 时使用System.exit(0)(我认为有办法检查)来重新启动应用程序。