【问题标题】:Android/Java - prevent OutOfMemoryError by detecting free RAM left before allocatingAndroid/Java - 通过在分配前检测剩余的空闲 RAM 来防止 OutOfMemoryError
【发布时间】:2015-05-27 20:15:21
【问题描述】:

在我的应用程序中,我正在处理一些文件。其中一些可能很大。当遇到一个文件太大而无法放入内存时,我想跳过它并礼貌地向用户解释这一点,最后显示其他文件的部分结果。这些文件是用BufferedReader 读入的,它在使用后被丢弃,没有原生的东西。我意识到加载它可能需要比文件大小更多的内存,所以我正在检查文件大小的 3 倍是否可用。

问题是我找不到检测应用程序剩余可用内存的方法,并且在加载某些文件时总是会出现OutOfMemoryError。我已经搜索了所有内容,但对此没有明确的答案。我没有运气尝试过的事情:

1)

MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;

这会返回一个巨大的数字,几百兆字节,这显然远远超过了每应用程序堆数兆字节的限制。不用说,应用程序崩溃了。

2)

Runtime info = Runtime.getRuntime();
long freeSize = info.freeMemory();

这个数字通常在几兆左右,看起来是正确的,但如果与它比较 3 倍的文件大小,仍然会出现 OutOfMemoryError

3)

Runtime info = Runtime.getRuntime();
long freeSize = info.maxMemory() - info.totalMemory();

比上面的数字大一点,但还是会发生崩溃

4)

Debug.MemoryInfo mi = new Debug.MemoryInfo();
Debug.getMemoryInfo(mi);

我什至无法理解这个对象中的数据,但我觉得在这种情况下它不会有用

5)

ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
long freeMem = activityManager.getMemoryClass()*1024*1024 - Runtime.getRuntime().totalMemory();

再次崩溃。

6)

打电话

Runtime.getRuntime().gc();

在每个文件读取之前没有任何影响

处理的性质(正则表达式匹配)要求整个文件存在于内存中并且不能以块的形式加载。这是因为正则表达式需要随机访问字符读取,这对于文本文件是不可能的,因为字符集编码不同,至少性能不可接受。

那么这个看似简单的任务如何实现呢?

【问题讨论】:

  • 你在“处理”什么
  • 你的应用程序应该使用更少的内存...没有其他办法...并不总是OOME意味着没有可用内存...也可能是堆碎片问题...
  • @tyczj 正则表达式搜索,没什么特别的

标签: java android memory garbage-collection out-of-memory


【解决方案1】:

那么这个看似简单的任务如何实现呢?

在带有 ART 的 Android 5.x 上,您的一种方法有时可能会奏效。在较早版本的 Android 上,以及在 Android 5.x 上已经出现一段时间的应用程序中,您的任何方法都不起作用,因为您误解了问题。

问题不在于您的内存不足,尽管有错误的名称。问题是没有足够大的可用内存块来处理分配请求,并且您已达到堆限制,因此我们无法从操作系统分配更多 RAM。那是因为 Android 垃圾收集器不是一个压缩垃圾收集器,所以堆可以被碎片化。例外情况是在 ART 下运行时,在 Android 5.0+ 上,当您的应用在后台时,堆将被压缩(缓慢)。

AFAIK,Android 中没有 API 可以告诉您可以成功分配多大的内存块。

【讨论】:

  • 哎哟!但这是否意味着任何 Android 应用如果不 100% 重用其 Java 对象,迟早会崩溃?
  • @OrlinGeorgiev:不。应用程序可能永远不需要接近其堆限制。 Android 会终止后台进程以为其他进程释放系统 RAM,这意味着当您的应用程序运行时,它很有可能从一个新的堆开始。话虽如此,由于堆限制和非压缩 GC,OutOfMemoryError 在 Android 中比在传统 Java 环境中更常见
【解决方案2】:

如果您还没有,请查看 Google 的开发人员指南,了解 Managing Your Apps Memory,特别是标有“检查您应该使用多少内存”的部分。该部分说明了有关确定应用程序的每个设备堆大小以及可以安全分配的内容:

您可以致电getMemoryClass() 来估算您应用的可用堆(以 MB 为单位)。如果您的应用尝试分配的内存超出此处可用的内存,它将收到 OutOfMemoryError。

了解给定设备的实际堆大小可以让您动态确定可以为设备分配的最大文件大小。

【讨论】:

  • 这是方法 5) 但它失败了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-16
  • 1970-01-01
  • 2018-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多