java - Android/Java - 通过在分配之前检测剩余的可用 RAM 来防止 OutOfMemoryError

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

在我的应用程序中,我正在处理一些文件。其中一些可能很大。当遇到太大而无法放入内存的文件时,我想跳过它并礼貌地向用户解释这一点,最后显示其他文件的部分结果。这些文件是用 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();

在每个文件读取之前没有任何效果

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

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

最佳答案

So how can this seemingly simple task be achieved?

在 Android 5.x 上,使用 ART,您的方法之一有时可能会起作用。在较旧版本的 Android 上,以及对于在 Android 5.x 上已在前台运行一段时间的应用程序,您的方法都不起作用,因为您误解了问题。

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

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

关于java - Android/Java - 通过在分配之前检测剩余的可用 RAM 来防止 OutOfMemoryError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29233983/

相关文章:

java - 注解Spring @Controller也作为Bean?

c++ - 类(class)访问违规阅读位置

c++ - 为什么悬挂指针引用会使程序崩溃

java - 将 JTable 内容保存为文本文件

java - 在Java中查找数组中的元素

java stream List<Map<String,Double>> 需要根据字符串取平均值

android - 该项目缺少构建所需的 Android SDK

android - 您如何区分 onPause() 由于 onNewIntent 与 android 中的用户操作

android - 在 fragment 内初始化 map

c# - .NET 中 DataTable 或其他复杂对象的最大大小