我使用了/proc/meminfo并解析了命令响应,但结果显示:
MemTotal:94348 kB MemFree:5784 kB
这意味着只有5MB的空闲内存。在Android手机上是否可能出现这种情况? 我的手机上只安装了5-6个应用程序,并且没有其他任务正在运行。但是这个命令仍然显示非常少的可用内存。
有人能澄清一下吗?或者是否有其他获取Android内存使用情况的方法?
我使用了/proc/meminfo并解析了命令响应,但结果显示:
MemTotal:94348 kB MemFree:5784 kB
这意味着只有5MB的空闲内存。在Android手机上是否可能出现这种情况? 我的手机上只安装了5-6个应用程序,并且没有其他任务正在运行。但是这个命令仍然显示非常少的可用内存。
有人能澄清一下吗?或者是否有其他获取Android内存使用情况的方法?
注意:本答案测量的是设备的内存使用/可用情况,而不是您的应用程序可用情况。要测量您的应用程序正在执行的操作以及允许执行的操作,请使用 Android 开发者的回答。
Android 文档 - ActivityManager.MemoryInfo
解析 /proc/meminfo 命令。您可以在这里找到参考代码:获取 Android 中的内存使用情况。
使用下面的代码获取当前 RAM:
MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
double availableMegs = mi.availMem / 0x100000L;
//Percentage can be calculated for API 16+
double percentAvail = mi.availMem / (double)mi.totalMem * 100.0;
0x100000L数值的解释
1024 bytes == 1 Kibibyte
1024 Kibibyte == 1 Mebibyte
1024 * 1024 == 1048576
1048576 == 0x100000
很明显,这个数字用于将字节转换成Mebibyte。
P.S:我们只需要计算总内存一次。因此,在您的代码中仅调用点1一次,然后可以重复调用点2的代码。
这取决于您希望获取的内存查询的定义。
通常,您需要了解堆内存的状态,因为如果它使用过多的内存,您将收到OOM并使应用程序崩溃。
为此,您可以检查以下值:
final Runtime runtime = Runtime.getRuntime();
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;
当"usedMemInMB"变量接近"maxHeapSizeInMB"时,availHeapSizeInMB
越接近于零,离OOM就越近。(由于内存碎片化,可能在达到零之前就会发生OOM。)
这也是内存使用的DDMS工具显示的内容。
另外,还有实际的RAM使用情况,即整个系统使用了多少RAM-查看被接受的答案以计算它。
更新:自Android O开始,您的应用程序也会使用本地RAM(至少用于位图存储,这通常是巨大的内存使用的主要原因),而不仅仅是堆,因此情况已经改变,并且您会获得更少的OOM(因为堆不再包含位图,请参见此处),但如果您怀疑存在内存泄漏,仍然应该注意内存使用情况。在Android O上,如果您有可能导致旧版本OOM的内存泄漏,似乎它将会在没有您能够捕捉到的情况下崩溃。以下是检查内存使用情况的方法:
val nativeHeapSize = Debug.getNativeHeapSize()
val nativeHeapFreeSize = Debug.getNativeHeapFreeSize()
val usedMemInBytes = nativeHeapSize - nativeHeapFreeSize
val usedMemInPercentage = usedMemInBytes * 100 / nativeHeapSize
但我认为最好使用IDE的性能分析工具,它以图形方式实时显示数据。
因此,在Android O上的好消息是,由于存储过多的大型位图而导致崩溃变得更加困难,但坏消息是我不认为在运行时捕获这种情况是可能的。
编辑:似乎Debug.getNativeHeapSize()
会随时间改变,因为它向您显示应用程序的总最大内存。因此,这些函数仅用于性能分析工具,以显示您的应用程序使用了多少内存。
如果您想获取真正的总本地RAM和可用RAM,请使用以下方法:
val memoryInfo = ActivityManager.MemoryInfo()
(getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).getMemoryInfo(memoryInfo)
val nativeHeapSize = memoryInfo.totalMem
val nativeHeapFreeSize = memoryInfo.availMem
val usedMemInBytes = nativeHeapSize - nativeHeapFreeSize
val usedMemInPercentage = usedMemInBytes * 100 / nativeHeapSize
Log.d("AppLog", "total:${Formatter.formatFileSize(this, nativeHeapSize)} " +
"free:${Formatter.formatFileSize(this, nativeHeapFreeSize)} " +
"used:${Formatter.formatFileSize(this, usedMemInBytes)} ($usedMemInPercentage%)")
以下是计算当前运行应用程序内存使用的方法:
public static long getUsedMemorySize() {
long freeSize = 0L;
long totalSize = 0L;
long usedSize = -1L;
try {
Runtime info = Runtime.getRuntime();
freeSize = info.freeMemory();
totalSize = info.totalMemory();
usedSize = totalSize - freeSize;
} catch (Exception e) {
e.printStackTrace();
}
return usedSize;
}
Runtime.freeMemory()
返回 0,而 Runtime.totalMemory()
只返回当前分配的内存。 - artem另一种方式(目前在我的G1上显示有25MB可用空间):
MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;
Linux的内存管理哲学是“空闲内存就是浪费内存”。
我认为接下来的两行将显示“缓冲区”中有多少内存和“高速缓存”中有多少内存。虽然它们之间有所不同(请不要问这个差异是什么 :) ),但它们都大致相当于用于缓存文件数据和元数据的内存量。
在Linux系统上,一个更有用的免费内存指南是使用free(1)
命令;在我的桌面上,它报告的信息如下:
$ free -m 总共 已用 空闲 共享的 缓冲区 高速缓存 内存: 5980 1055 4924 0 91 374 -/+ 缓存/空闲: 589 5391 交换: 6347 0 6347
“+/- 缓存/空闲”行是神奇的一行,它报告说我实际上有约589兆字节的活动所需进程内存和约5391兆字节的“空闲”内存,因为如果内存可能被更有利地用于其他用途,那么91+374兆字节的缓冲区/缓存内存可以被丢弃。
(我的机器已经开机3个小时了,几乎什么都没做,只是在stackoverflow上浏览,这就是为什么我有那么多空闲内存。)
如果Android没有安装free(1)
,您可以使用/proc/meminfo
文件自己计算;我只是喜欢free(1)
输出格式。 :)
cat /proc/meminfo
。它提供了更详细的信息,但是MemFree
、Buffers
和Cached
这几行可能是最重要的。 - sarnold我参考了一些文章。
参考资料:
这个getMemorySize()方法返回了具有总内存大小和可用内存大小的MemorySize。
我不完全相信这段代码。
这段代码是在LG G3 cat.6 (v5.0.1)上测试的。
private MemorySize getMemorySize() {
final Pattern PATTERN = Pattern.compile("([a-zA-Z]+):\\s*(\\d+)");
MemorySize result = new MemorySize();
String line;
try {
RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
while ((line = reader.readLine()) != null) {
Matcher m = PATTERN.matcher(line);
if (m.find()) {
String name = m.group(1);
String size = m.group(2);
if (name.equalsIgnoreCase("MemTotal")) {
result.total = Long.parseLong(size);
} else if (name.equalsIgnoreCase("MemFree") || name.equalsIgnoreCase("Buffers") ||
name.equalsIgnoreCase("Cached") || name.equalsIgnoreCase("SwapFree")) {
result.free += Long.parseLong(size);
}
}
}
reader.close();
result.total *= 1024;
result.free *= 1024;
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
private static class MemorySize {
public long total = 0;
public long free = 0;
}
我知道 Pattern.compile() 很耗费资源,因此您可以将其代码移动到类成员中。
public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
final long hiddenAppMem = mProcessList.getMemLevel(ProcessList.HIDDEN_APP_MIN_ADJ);
outInfo.availMem = Process.getFreeMemory();
outInfo.totalMem = Process.getTotalMemory();
outInfo.threshold = homeAppMem;
outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((hiddenAppMem-homeAppMem)/2));
outInfo.hiddenAppThreshold = hiddenAppMem;
outInfo.secondaryServerThreshold = mProcessList.getMemLevel(
ProcessList.SERVICE_ADJ);
outInfo.visibleAppThreshold = mProcessList.getMemLevel(
ProcessList.VISIBLE_APP_ADJ);
outInfo.foregroundAppThreshold = mProcessList.getMemLevel(
ProcessList.FOREGROUND_APP_ADJ);
}
在android.os.Process.java文件中:
/** @hide */
public static final native long getFreeMemory();
/** @hide */
public static final native long getTotalMemory();
它从android_util_Process.cpp调用JNI方法。
结论
MemoryInfo.availMem = /proc/meminfo中的MemFree + Cached。
注释
总内存在API级别16中添加。
/** accurate value under limitation */
int getAccurateAppUsedMemory() {
ActivityManager manager = context.getSystemService(Context.ACTIVITY_SERVICE);
Debug.MemoryInfo info = manager.getProcessMemoryInfo(new int[]{Process.myPid()})[0];
// Warning: there's a limitation of invocation frequency on Android Q or later
return info.getTotalPss(); // in kB
}
/** approximate value without limitation */
int getApproximateAppUsedMemory() {
Debug.MemoryInfo info = new Debug.MemoryInfo();
Debug.getMemoryInfo(info);
return info.getTotalPss(); // in kB
}
您还可以使用Android SDK自带的DDMS工具。它可以帮助获取Java代码和本地C / C ++代码的内存分配情况。
public static boolean isAppInLowMemory(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
return memoryInfo.lowMemory;
}
Debug.getNativeHeapFreeSize()
。 - IgorGanapolsky