Android/Java - 通过检测分配前剩余的空闲 RAM 来防止 OutOfMemoryError
Android/Java - prevent OutOfMemoryError by detecting free RAM left before allocating
在我的应用程序中,我正在处理一些文件。其中一些可能很大。当遇到文件大到内存放不下时,我想跳过它,礼貌地向用户解释一下,最后显示其他文件的部分结果。这些文件是用 BufferedReader
读入的,使用后会被丢弃,没有原生的东西。我意识到加载它可能需要比文件大小更多的内存,所以我正在检查文件大小的 3 倍是否可用。
问题是我找不到检测应用程序剩余可用内存的方法,并且在加载某些文件时总是出现 OutOfMemoryError
。我已经搜索了所有 SO,但对此没有明确的答案。我尝试过但没有成功的事情:
1)
MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;
这个 returns 一个巨大的数字,几百兆字节,这显然远远超过了每个应用程序几兆字节的堆限制。不用说,应用程序崩溃了。
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();
在每个文件读取之前没有任何效果
处理(正则表达式匹配)的性质要求整个文件存在于内存中,不能分块加载。这是因为正则表达式需要随机访问字符读取,这对于文本文件来说是不可能的,因为不同的字符集编码,至少不具有可接受的性能。
那么这个看似简单的任务是如何实现的呢?
So how can this seemingly simple task be achieved?
在 Android 5.x 上,使用 ART,您的其中一种方法有时可能会奏效。在 Android 的旧版本上,以及在 Android 5.x 上已经在前台运行了一段时间的应用程序,您的方法 none 会起作用,因为您误解了问题。
问题不在于您内存不足,尽管出现了错误名称。问题是 没有足够大的单个空闲内存块来处理分配请求,并且您已达到堆限制,因此我们无法从 OS 分配更多 RAM .那是因为 Android 垃圾收集器不是一个压缩垃圾收集器,所以堆可以被碎片化。例外情况是 运行 在 ART 下,在 Android 5.0+ 上,堆将在您的应用程序处于后台时(缓慢地)被压缩。
AFAIK,Android 中没有 API 会告诉您可以成功分配多大的内存块。
如果您还没有,请查看 Google 中关于 Managing Your Apps Memory 的开发人员指南,特别是标有“检查您应该使用多少内存”的部分。该部分在确定您的应用程序的每个设备堆大小以及希望可以安全分配的内容时说了这一点:
You can call getMemoryClass() to get an estimate of your app's available heap in megabytes. If your app tries to allocate more memory than is available here, it will receive an OutOfMemoryError.
了解给定设备的实际堆大小可以让您动态确定可以为设备分配的最大文件大小。
在我的应用程序中,我正在处理一些文件。其中一些可能很大。当遇到文件大到内存放不下时,我想跳过它,礼貌地向用户解释一下,最后显示其他文件的部分结果。这些文件是用 BufferedReader
读入的,使用后会被丢弃,没有原生的东西。我意识到加载它可能需要比文件大小更多的内存,所以我正在检查文件大小的 3 倍是否可用。
问题是我找不到检测应用程序剩余可用内存的方法,并且在加载某些文件时总是出现 OutOfMemoryError
。我已经搜索了所有 SO,但对此没有明确的答案。我尝试过但没有成功的事情:
1)
MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;
这个 returns 一个巨大的数字,几百兆字节,这显然远远超过了每个应用程序几兆字节的堆限制。不用说,应用程序崩溃了。
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();
在每个文件读取之前没有任何效果
处理(正则表达式匹配)的性质要求整个文件存在于内存中,不能分块加载。这是因为正则表达式需要随机访问字符读取,这对于文本文件来说是不可能的,因为不同的字符集编码,至少不具有可接受的性能。
那么这个看似简单的任务是如何实现的呢?
So how can this seemingly simple task be achieved?
在 Android 5.x 上,使用 ART,您的其中一种方法有时可能会奏效。在 Android 的旧版本上,以及在 Android 5.x 上已经在前台运行了一段时间的应用程序,您的方法 none 会起作用,因为您误解了问题。
问题不在于您内存不足,尽管出现了错误名称。问题是 没有足够大的单个空闲内存块来处理分配请求,并且您已达到堆限制,因此我们无法从 OS 分配更多 RAM .那是因为 Android 垃圾收集器不是一个压缩垃圾收集器,所以堆可以被碎片化。例外情况是 运行 在 ART 下,在 Android 5.0+ 上,堆将在您的应用程序处于后台时(缓慢地)被压缩。
AFAIK,Android 中没有 API 会告诉您可以成功分配多大的内存块。
如果您还没有,请查看 Google 中关于 Managing Your Apps Memory 的开发人员指南,特别是标有“检查您应该使用多少内存”的部分。该部分在确定您的应用程序的每个设备堆大小以及希望可以安全分配的内容时说了这一点:
You can call getMemoryClass() to get an estimate of your app's available heap in megabytes. If your app tries to allocate more memory than is available here, it will receive an OutOfMemoryError.
了解给定设备的实际堆大小可以让您动态确定可以为设备分配的最大文件大小。