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