【问题标题】:How to get current memory usage in android?如何在android中获取当前的内存使用情况?
【发布时间】:2011-03-11 09:15:32
【问题描述】:

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

内存总量:94348 kB 无内存:5784 kB

的意思。它显示只有 5MB 可用内存。安卓手机可以吗? 我的手机上只安装了 5-6 个应用程序,没有其他任务正在运行。但是这个命令仍然显示可用内存很少。

有人可以澄清一下吗?或者有没有其他方法可以在 android 中获取内存使用情况?

【问题讨论】:

  • 您想查看每个设备或每个应用程序的可用内存吗?如果每个应用程序,则需要在堆上计算 a-la Debug.getNativeHeapFreeSize()
  • 要使用 /proc/meminfo 计算空闲内存(在 RAM 中),您必须获取 MemFreeBuffersCached 的聚合SwapCached。 Android 提供了一个用于此目的的 API,适用于 API 16 和病房。如果您针对的是较旧的 API,Meminfo 会很有帮助。

标签: android memory-management


【解决方案1】:

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

我假设接下来的两行将显示“缓冲区”中有多少内存以及“缓存”有多少。虽然两者之间存在差异(请不要问差异是什么:)它们都大致加起来用于缓存文件数据和元数据的内存量。

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

$免费-m 缓存的已用空闲共享缓冲区总数 电话:5980 1055 4924 0 91 374 -/+ 缓冲区/缓存:589 5391 交换:6347 0 6347

+/- buffers/cache: 行是神奇的行,它报告我确实有大约 589 megs 的主动需要的进程内存,以及大约 5391 megs 的“空闲”内存,在这个意义上说 91如果内存可以更有利地用于其他地方,则可以丢弃 +374 兆字节的缓冲区/缓存内存。

(我的机器已经启动了大约三个小时,除了 stackoverflow 几乎什么都不做,这就是我有这么多空闲内存的原因。)

如果 Android 未附带 free(1),您可以使用 /proc/meminfo 文件自己计算;我只是喜欢free(1) 输出格式。 :)

【讨论】:

  • @Igor,那么你会想要cat /proc/meminfo。它更详细,但MemFreeBuffersCached 可能是最重要的几行。
【解决方案2】:

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

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

【讨论】:

  • 嗨,亚历克斯,非常感谢您的帮助!还有1个问题。这段代码给了我可用的 RAM。我还想显示总 RAM。如何获得?
  • @Badal 我不知道 Java API。坚持解析/proc/meminfo。
【解决方案3】:

注意:此答案测量设备的内存使用/可用情况。这不是您的应用程序可用的。要衡量您的 APP 正在做什么以及被允许做什么,Use android developer's answer


Android docs - ActivityManager.MemoryInfo

  1. 解析 /proc/meminfo 命令。您可以在此处找到参考代码:Get Memory Usage in 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

很明显,数字是用来从字节转换为兆字节的

P.S:我们只需要计算一次总内存。所以在你的代码中只调用点 1 一次,然后你可以重复调用点 2 的代码。

【讨论】:

  • 我想查看内存大小。MemoryInfo是什么?
  • PIraba,它的 android API 类。在这里查看developer.android.com/reference/android/app/…
  • @SanjayJoshi 那是因为availMem 变量包含以字节为单位的内存。 1024 字节等于 1 千字节,1024 千字节等于 1 兆字节。所以 1024 * 1024 等于 1048576
  • 转换为上面的两倍,否则 percentAvail 将为 0
  • @Rolfツ 抱歉,1024 字节等于 1 千字节,1024 字节等于 1 千字节。 Kilo 和 Mega 是十进制前缀。 1000 字节 = 1 千字节。这在答案中也有错误的解释。
【解决方案4】:

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

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;

}

【讨论】:

  • 这是一种简单的方法,但正如文档中所指出的,运行时类 freeMemory() 方法返回当前程序或应用程序的可用内存。所以在使用时要注意这一点。
  • @Peter - 是的,这是“错误的”,因为它回答的问题与被问到的问题不同。另一方面,这对于应用程序开发人员通常需要知道的内容来说是“正确的”:设备上的总体内存状态几乎不重要——如果用户运行了很多应用程序,操作系统应该 i> 充分利用它的大部分内存——否则效率低下。操作系统需要知道接受的答案给出了什么,知道什么时候开始杀死最近没有使用过的应用程序。但是应用程序员需要知道这个答案(以及 android 开发者的类似答案)告诉你什么,而不是 runtime.maxMemory。
  • 此解决方案仅适用于运行时暴露给应用程序的内存。这并不能像 OP 所要求的那样深入了解整个系统内存。
  • 在许多设备上(例如小米)Runtime.freeMemory() 返回 0,Runtime.totalMemory() 仅返回当前分配的内存。
【解决方案5】:

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

【讨论】:

    【解决方案6】:

    我查看了 Android 源代码树。

    在 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 中添加了总内存。

    【讨论】:

      【解决方案7】:

      这取决于您对希望获得的内存查询的定义。


      通常,您想知道堆内存的状态,因为如果它使用过多的内存,您会得到 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 使用量,即整个系统使用了多少 - 请参阅 accepted answer 来计算。


      更新:由于 Android O 使您的应用也使用本机 RAM(至少对于位图存储而言,这通常是使用大量内存的主要原因),而不仅仅是堆,因此发生了变化,并且您获得的 OOM 更少(因为堆不再包含位图,请检查here),但是如果您怀疑您有内存泄漏,您仍然应该注意内存使用。在 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%)")
      

      【讨论】:

      • 哇。如此简单,却又如此真实!
      • 实际内存使用量是多少?所以在这种情况下 usedMemInMB 不是应用程序的实际内存使用情况吗?当我使用此代码时,它显示我的使用量是 50mb,但是当我进入手机设置并查看那里的内存使用情况时,我的应用程序显示 100mb。为什么会有这种差异?
      • @batmaci 堆内存只是应用程序总内存使用量的一部分。还有本机内存使用,通常用于网页、游戏和一些重度用途。通常应用只需要查看堆内存,因为它与设备 RAM 相比非常低,如果达到,应用就会崩溃(即使有足够的空闲 RAM)。
      • 完美的sn-p代码,对OOM检查非常有用,非常感谢。
      • @AlphaOF 谢谢,但 Android O 上的情况发生了变化。我已经更新了答案以匹配那里的情况。
      【解决方案8】:

      我参考了几篇文章。

      参考:

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

      【讨论】:

        【解决方案9】:
        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;
        }
        

        【讨论】:

          【解决方案10】:
          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 没有被使用?

          【讨论】:

            【解决方案11】:

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

            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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-11-05
              • 2020-11-12
              • 2016-06-22
              • 2011-03-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-07-30
              相关资源
              最近更新 更多