我有一个恼人的问题:
我从服务器获取了很多GeoJSON数据。即使我有16MB堆,即使我多次启动和停止应用程序,这也可以。内存消耗保持不变,永不超过。但是有一种情况我超过16MB堆。我想很快描述一下:
应用程序使用并通过主页按钮“退出”,因此应用程序驻留在后台并且尚未销毁。当应用程序恢复时,我的“控制器”(我的应用程序的一部分)会检查新的GeoJSON数据。如果有GeoJSON数据更新,应用程序会下载并处理它,此处问题就出现了。如果应用程序之前已经启动并从后台恢复,那么16MB的堆大小对于以下代码来说是不够的(当且仅当应用程序从后台恢复而不是重新开始时):< / p>
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();
}
我在追加()或 toString()中获取OutOfMemory。显然,当以前以某种方式使用时,应用程序对此几乎没有太大的记忆。我已经尝试为上面的代码找到更加资源友好的方式,但没有解决方案。同样,如果应用程序是从新的启动,则永远不会出现问题。而且我绝对相信我没有任何内存泄漏,因为
如果会有内存泄漏,它会在第3次第4次以24MB堆崩溃后崩溃,但它运行没有问题。
我知道如何避免崩溃。我可以向用户显示AlertDialog,告诉他有新的GeoJSON数据,他需要重新启动应用程序。但是有一个问题!如果应用程序被Activity的 finish()“终止”,则应用程序仍然保留在内存中,因此当它重新启动时,崩溃再次发生,因为内存永远不会被释放(至少我不能依赖它)在大多数情况下)。我已经发现 System.exit(0); 而不是完成将释放所有内存,因为它会杀死整个应用程序,因此在使用新的GeoJSON数据重新启动后不会发生崩溃。但我知道这不是一个好的解决方案。我已经在重要部分上尝试过 System.gc(),但这也不起作用。任何想法如何处理这个问题?可能我需要重新启动所有已用内存来重启应用程序。
另一种解决方案可能是重新设计上面的代码,但我认为不可能从中获得更多的MB。
如果我找不到合理的解决方案,我会使用 System.exit(0)当堆是16MB(我认为有办法检查)重启应用程序
答案 0 :(得分:0)
这里有一些想法:
一旦您知道有任何要阅读的内容,请将旧数据设置为空,以便进行GC编辑。
使用执行此任务的服务,该服务将在不同的进程上运行(因此,此任务至少具有16 MB)。一旦它处理数据,就以某种方式将它移动到你需要的任何组件,同时将之前的旧数据置零。
在获取数据时解码数据,而不是获取所有数据然后对其进行解码。
压缩数据,以便在解码时,它会在途中解压缩。
使用json的替代方法,例如google的protocol buffers或您自己的自定义数据类型。
其中大多数设备的堆内存都超过16 MB。您可以简单地将min sdk版本设置为8或10,因为大多数内存比此更多的设备也具有更高的API。
答案 1 :(得分:0)
感谢您的回答。最后,我决定让System.exit(0)处于这种特殊情况,因为数据几乎没有更新过,即使有人巧妙地发现它确实发生在有人让应用程序在后台运行时。