如何获取Android中的当前内存使用情况?


108

我已经使用了/ proc / meminfo并解析了命令response。但是结果表明:

内存总计:94348 kB内存空闲:5784 kB

手段。它显示只有5MB的可用内存。Android Mobile可能吗?我的手机上仅安装了5-6个应用程序,没有其他任务在运行。但是此命令仍然显示可用内存很少。

有人可以澄清吗?还是有任何其他方式来获取android中的内存使用情况?


2
您是否要查看每个设备或每个应用程序的可用内存?如果是每个应用程序,则需要在堆a-la上进行计算Debug.getNativeHeapFreeSize()
IgorGanapolsky '16

1
要使用/ proc / meminfo计算可用内存(在RAM中),您必须获取MemFreeBuffersCachedSwapCached的集合。Android为此提供了一个API,可在API 16和病区上使用。如果您要定位较旧的API,则Meminfo会很有帮助。
AB

Answers:


174

注意:此答案用于衡量设备的内存使用情况/可用空间。这不是您的应用可用的功能。要衡量您的APP在做什么以及被允许做什么,请使用android开发人员的答案


Android文档-ActivityManager.MemoryInfo

  1. 解析/ proc / meminfo命令。您可以在此处找到参考代码:获取Android中的内存使用情况

  2. 使用下面的代码并获取当前的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

很明显,该数字用于将字节转换为兆字节

PS:我们只需要计算一次总内存。因此,在代码中只调用一次点1,然后再调用一次,就可以重复调用点2的代码。


我要检查内存大小。什么是MemoryInfo?
皮拉巴

PIraba,其android API类。在此处检查developer.android.com/reference/android/app/…
Badal

@SanjayJoshi那是因为availMem变量包含以字节为单位的内存。1024字节等于1千字节,而1024千字节等于1兆字节。所以1024 * 1024等于1048576
Rolf

2
转换为两倍以上,否则percentAvail将为0
blueether

1
@Rolfツ抱歉,但1024字节等于1 Kibibyte,而1024 Kibibyte是1 MibiByte。Kilo和Mega是十进制前缀。1000字节= 1千字节。答案中也有错误解释。
JacksOnF1re

88

这取决于您对要获取的内存查询的定义。


通常,您想知道堆内存的状态,因为如果堆内存使用过多,则会出现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使用量,即整个系统使用的内存量-请参阅可接受的答案进行计算。


更新:由于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上的一个好消息是,由于OOM存储了太多的大位图而导致崩溃更加困难,但是坏消息是,我认为在运行时无法捕获这种情况。


编辑:似乎Debug.getNativeHeapSize()随着时间的变化,因为它显示您的应用程序的总最大内存。因此,这些功能仅用于探查器,以显示您的应用程序正在使用多少。

如果要获取实际的总可用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%)")

哇。如此简单,却如此真实!
2013年

实际的内存使用量是多少?所以usedMemInMB在这种情况下不是应用程序的实际内存使用情况吗?当我使用此代码时,它显示出我的使用情况约为50mb,但是当我转到手机设置并看到那里的内存使用情况时,我的应用程序显示为100mb。为什么有这种区别?
batmaci

1
@batmaci堆内存只是应用程序总内存使用量的一部分。还有本机内存使用情况,通常用于网页,游戏和一些繁重的目的。通常,应用程序只需要查看堆内存,因为与设备RAM相比,该内存已经很低了,如果到达内存,应用程序将崩溃(即使有足够的可用RAM)。
Android开发人员

这是一个完美的代码段,对检查OOM非常有用,非常感谢。
aolphn

@AlphaOF谢谢,但是Android O上的情况已经改变。我已经更新了答案以匹配当地的情况。
Android开发人员

29

这是一种计算当前正在运行的应用程序的内存使用量的方法

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;

}

4
这是一种简单的方法,但是正如文档中指出的那样,运行时类freeMemory()方法返回当前程序或应用程序的可用内存。因此在使用时要注意这一点。
Aksel Fatih

2
@Peter-是的,这是“错误的”,因为它回答的问题与提出的问题不同。另一方面,对于应用程序开发人员通常需要知道的事情来说,这是“正确的”:DEVICE上的整体内存状态是什么并不重要-如果用户运行了很多应用程序,则操作系统利用大部分它的内存-否则效率低下。操作系统需要知道接受的答案,知道何时开始杀死最近未使用过的应用程序。但是,应用程序程序员需要知道此答案(和android开发人员的类似答案)告诉您什么,与runtime.maxMemory相比。
ToolmakerSteve

该解决方案仅适用于运行时暴露给应用程序的内存。这并不能提供OP所需的有关整个系统内存的见解。
AB:

在许多设备(例如Xiaomi)上,Runtime.freeMemory()返回0并Runtime.totalMemory()仅返回当前分配的内存。
artem

17

另一种方式(当前在我的G1上显示25MB的可用空间):

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

嘿Alex,非常感谢您的帮助!还有1个问题。这段代码为我提供了可用的RAM。我还想显示总RAM。如何获得?
Badal

@Badal我不知道该使用Java API。坚持解析/ proc / meminfo。
扬琴科

12

Linux的内存管理理念是“空闲内存就是浪费的内存”。

我假设接下来的两行将显示“缓冲区”中有多少内存,以及“缓存”中有多少内存。尽管两者之间有区别(请不要问那是什么区别:),它们两者的总和大约等于用于缓存文件数据和元数据的内存量。

free(1)命令是在Linux系统上释放内存的更有用的指南。在我的桌面上,它报告如下信息:

$ free -m
             已使用的可用共享缓冲区总数
内存:5980 1055 4924 0 91374
-/ +缓冲区/缓存:589 5391
掉期:6347 0 6347

+/- buffers / cache:行是神奇的行,它报告说我确实有大约589兆的活动需要的进程内存和大约5391兆的“可用”内存,也就是说91 + 374兆字节如果可以在其他地方更有利地使用该内存,则可以丢弃一部分缓冲区/缓存的内存。

(我的机器已经运行了大约三个小时,除了stackoverflow几乎什么都不做,这就是为什么我有这么多可用内存的原因。)

如果Android不附带free(1),则您可以自己对该/proc/meminfo文件进行数学计算;我只是喜欢free(1)输出格式。:)


1
@Igor,那么您将想要cat /proc/meminfo代替。它要详细得多,但是MemFreeBuffers,并且Cached可能是最重要的行。
sarnold

6

我引用的著作很少。

参考:

此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()的成本很高,因此您可以将其代码移至类成员。


3

我看了看Android Source Tree。

在com.android.server.am内部。ActivityManagerService.java(由android.app。暴露的内部服务ActivityManager)。

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 = MemFree +缓存在/ proc / meminfo中。

笔记

总内存已添加到API级别16中。


1

您还可以使用DDMS工具,该工具本身就是android SDK的一部分。它还有助于获取Java代码和本机c / c ++代码的内存分配。


0
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;
}

0
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;

这是一个奇怪的代码。它返回MaxMemory-(totalMemory-freeMemory)。如果freeMemory等于0,则代码将返回MaxMemory-totalMemory,因此它可以大于或等于0。为什么不使用freeMemory?


0

这是查看应用程序内存使用情况的另一种方法:

adb shell dumpsys meminfo <com.package.name> -d

样本输出:

Applications Memory Usage (kB):
Uptime: 2896577 Realtime: 2896577

** MEMINFO in pid 2094 [com.package.name] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     3472     3444        0        0     5348     4605      102
  Dalvik Heap     2349     2188        0        0     4640     4486      154
 Dalvik Other     1560     1392        0        0
        Stack      772      772        0        0
    Other dev        4        0        4        0
     .so mmap     2749     1040     1220        0
    .jar mmap        1        0        0        0
    .apk mmap      218        0       32        0
    .ttf mmap       38        0        4        0
    .dex mmap     3161       80     2564        0
   Other mmap        9        4        0        0
      Unknown       76       76        0        0
        TOTAL    14409     8996     3824        0     9988     9091      256

 Objects
               Views:       30         ViewRootImpl:        2
         AppContexts:        4           Activities:        2
              Assets:        2        AssetManagers:        2
       Local Binders:       17        Proxy Binders:       21
    Death Recipients:        7
     OpenSSL Sockets:        0

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

对于整体内存使用情况:

adb shell dumpsys meminfo

https://developer.android.com/studio/command-line/dumpsys#meminfo

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.