如何强制Android应用程序释放所有内存?

如何强制Android应用程序释放所有内存?,android,out-of-memory,heap-memory,Android,Out Of Memory,Heap Memory,我有一个恼人的问题: 我正在从服务器获取大量GeoJSON数据。即使使用16MB堆,即使我多次启动和停止应用程序,这种方法也能奏效。内存消耗保持不变,从不超过。但有一种情况是我超过了16MB堆。我想简单描述一下: 该应用程序已被使用,并通过“主页”按钮“退出”,因此该应用程序驻留在后台,尚未销毁。当应用程序恢复时,作为应用程序一部分的“控制器”会检查新的GeoJSON数据。如果有GeoJSON数据更新,应用程序将下载并处理它,然后问题就开始了。如果应用程序之前已经启动,并且是从后台恢复的,则16

我有一个恼人的问题:
我正在从服务器获取大量GeoJSON数据。即使使用16MB堆,即使我多次启动和停止应用程序,这种方法也能奏效。内存消耗保持不变,从不超过。但有一种情况是我超过了16MB堆。我想简单描述一下:
该应用程序已被使用,并通过“主页”按钮“退出”,因此该应用程序驻留在后台,尚未销毁。当应用程序恢复时,作为应用程序一部分的“控制器”会检查新的GeoJSON数据。如果有GeoJSON数据更新,应用程序将下载并处理它,然后问题就开始了。如果应用程序之前已经启动,并且是从后台恢复的,则16MB的堆大小对于以下代码来说是不够的(如果且仅当应用程序是从后台恢复而不是从新启动时)):

我在append()toString()中获得内存。很明显,当以前以某种方式使用该应用程序时,它只需要很少或更多的内存。我已经试着为上面的代码找到一种资源更友好的方法,但是没有解决方案。同样,如果应用程序是从新启动的,则不会出现问题。我绝对确信我没有任何内存泄漏,因为

  • 我用MAT检查了这部分和更多内容,从来没有占用超过1.6MB的空间(这是GeoJSON数据)
  • 我以24MB的堆大小连续执行了这个用例几次 如果出现内存泄漏,它将在第3次或第4次使用24MB堆后崩溃,但运行时没有问题

    我知道如何避免撞车。我可以向用户显示一个AlertDialog,告诉他有新的GeoJSON数据可用,他需要重新启动应用程序。但有一个陷阱。如果应用程序被活动的finish()“终止”,应用程序仍保留在内存中,因此当它重新启动时,崩溃再次出现,因为内存从未释放(至少在大多数情况下我不能依赖它)。我已经计算出系统退出(0)而不是finish将释放所有内存,因为它会杀死整个应用程序,因此在使用新的GeoJSON数据重新启动后不会发生崩溃。但我知道这不是一个好办法。我已经在重要部件上尝试了System.gc(),但这也不起作用。有没有办法解决这个问题?可能我需要重新启动应用程序,释放所有已用内存

    另一个解决方案是重新设计上面的代码,但我认为不可能从中获得更多MBs

    如果我找不到合理的解决方案,我会在堆容量为16MB时使用System.exit(0)
    重新启动应用程序。

    以下是一些想法:

  • 一旦您知道有任何内容要读取,就将旧数据设置为null,以便对其进行GC读取

  • 使用执行此任务的服务,该服务将在不同的进程上运行(因此,仅此任务至少有16 mb)。一旦它处理了数据,就以某种方式将其移动到您需要的任何组件,同时在之前为旧数据设置空值

  • 在获取数据时对其进行解码,而不是获取所有数据然后对其进行解码

  • 压缩数据,以便在解码数据时,它将在途中解压缩数据

  • 使用json的替代方法,例如google或您自己的自定义数据类型

  • 大多数设备的堆内存都超过16MB。您可以简单地将min sdk版本设置为8或10,因为大多数内存超过此值的设备也具有更高的API


  • 谢谢你的回答。最后,我决定在这种特殊情况下让System.exit(0)退出,因为数据几乎从未更新过,即使是这样,也一定是巧合,它恰好发生在有人在后台运行应用程序时。

    。这与内存使用无关,因此与问题无关。在任何情况下,如果一个服务需要做一些花费很长时间的事情,它可以创建一个线程,甚至使用通知将自己设置为前台。内存不足。我的版本是4。大多数ppl使用的是安卓2.3.3,所以我不能超过版本7或8.API 8是安卓2.2。有关详细信息,请参阅此链接上的图表:。此外,有关全球android版本的统计信息,请参见:@android我刚才说的“使用完成此任务的服务”本身不会改变任何东西,因为一个简单的服务与应用程序的其余部分在同一个进程中运行。如果你的“控制器”当应用程序在两次连续下载之间未暂停时获取新数据?我将不得不为此重新设计整个应用程序,但这几乎不是一个选项,因为对于很少使用的设备来说,这将是一个很大的工作,这些设备很少用于不经常出现的用例,因为这只是应用程序出现在前台时的一个问题。此外,数据几乎从未更新过。(我猜是一年两次或三次)。对不起,我不是说这是一个建议的解决方案,而是一个测试,看看这个问题是否与应用程序在这段时间内暂停/恢复有关。
    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();
    }