如何在Android中发现我的应用程序的内存使用情况?

如何通过编程的方式找到我的Android应用程序中使用的内存?

我希望有办法做到这一点。 另外,我如何获得手机的免费记忆?


请注意,像Linux这样的现代操作系统的内存使用情况是一个非常复杂且难以理解的领域。 事实上,你实际上正确解释你得到的数字的机会是非常低的。 (几乎每次我与其他工程师一起查看内存使用量数字时,总会长时间讨论它们的实际含义,结果只会导致一个模糊的结论。)

注意:我们现在有更多关于管理您的应用程序内存的大量文档,其中涵盖了大部分内容,并且更新了Android的状态。

首先,可能会阅读本文的最后部分,其中讨论了如何在Android上管理内存:

服务API更改从Android 2.0开始

现在ActivityManager.getMemoryInfo()是我们用于查看整体内存使用情况的最高级别API。 这主要是为了帮助应用程序衡量系统距离后台进程没有更多内存有多近,因此需要开始查杀所需的进程(如服务)。 对于纯Java应用程序,这应该没什么用处,因为Java堆限制的存在部分是为了避免一个应用程序能够将系统强调到这一点。

在较低层次上,您可以使用调试API来获取关于内存使用情况的原始内核级信息:android.os.Debug.MemoryInfo

注意,从2.0开始,还有一个API, ActivityManager.getProcessMemoryInfo ,用于获取有关另一个进程的信息:ActivityManager.getProcessMemoryInfo(int [])

这将返回一个包含所有这些数据的低级别MemoryInfo结构:

    /** The proportional set size for dalvik. */
    public int dalvikPss;
    /** The private dirty pages used by dalvik. */
    public int dalvikPrivateDirty;
    /** The shared dirty pages used by dalvik. */
    public int dalvikSharedDirty;

    /** The proportional set size for the native heap. */
    public int nativePss;
    /** The private dirty pages used by the native heap. */
    public int nativePrivateDirty;
    /** The shared dirty pages used by the native heap. */
    public int nativeSharedDirty;

    /** The proportional set size for everything else. */
    public int otherPss;
    /** The private dirty pages used by everything else. */
    public int otherPrivateDirty;
    /** The shared dirty pages used by everything else. */
    public int otherSharedDirty;

但是至于PssPrivateDirtySharedDirty之间的区别是什么......现在好玩开始了。

Android(以及一般的Linux系统)中的大量内存实际上是在多个进程间共享的。 所以一个进程使用多少内存真的不清楚。 在该页面的顶部添加磁盘(更不用说我们在Android上不使用的swap了),而且更加不清楚。

因此,如果您要将实际映射到每个进程的所有物理RAM,并将所有进程相加,那么最终可能会得到比实际总RAM更大的数字。

Pss编号是内核计算时考虑到内存共享的度量标准 - 基本上,进程中的每个RAM页面都按照使用该页面的其他进程数量的比例进行缩放。 通过这种方式,您可以(理论上)在所有进程中添加pss以查看它们正在使用的总RAM,并比较进程之间的pss以粗略了解它们的相对权重。

这里另一个有趣的指标是PrivateDirty ,它基本上是进程内部的RAM数量,不能被分页到磁盘(它不受磁盘上的相同数据支持),并且不与任何其他进程共享。 另一种看待这个问题的方法是当这个进程消失时(也可能很快包含到缓存和其他用途中),系统可以使用的RAM。

这几乎是SDK的API。 但是,您可以使用设备作为开发人员进行更多操作。

使用adb ,您可以获得关于正在运行的系统的内存使用情况的大量信息。 一个常见的命令是adb shell dumpsys meminfo命令,该命令将吐出关于每个Java进程的内存使用情况的大量信息,其中包含上述信息以及各种其他信息。 您还可以使用单个进程的名称或pid来查看,例如adb shell dumpsys meminfo system给我系统进程:

** MEMINFO in pid 890 [system] **
                    native   dalvik    other    total
            size:    10940     7047      N/A    17987
       allocated:     8943     5516      N/A    14459
            free:      336     1531      N/A     1867
           (Pss):     4585     9282    11916    25783
  (shared dirty):     2184     3596      916     6696
    (priv dirty):     4504     5956     7456    17916

 Objects
           Views:      149        ViewRoots:        4
     AppContexts:       13       Activities:        0
          Assets:        4    AssetManagers:        4
   Local Binders:      141    Proxy Binders:      158
Death Recipients:       49
 OpenSSL Sockets:        0

 SQL
            heap:      205          dbFiles:        0
       numPagers:        0   inactivePageKB:        0
    activePageKB:        0

上面的部分是主要原因之一,其中size是在一个特定的堆的地址空间总大小, allocated是实际分配的KB是堆认为它有, free是剩余Kb免费堆有额外拨款,以及psspriv dirty与之前讨论的特定于与每个堆关联的页面相同。

如果您只想查看所有进程的内存使用情况,则可以使用命令adb shell procrank 。 这在同一个系统上的输出如下所示:

  PID      Vss      Rss      Pss      Uss  cmdline
  890   84456K   48668K   25850K   21284K  system_server
 1231   50748K   39088K   17587K   13792K  com.android.launcher2
  947   34488K   28528K   10834K    9308K  com.android.wallpaper
  987   26964K   26956K    8751K    7308K  com.google.process.gapps
  954   24300K   24296K    6249K    4824K  com.android.phone
  948   23020K   23016K    5864K    4748K  com.android.inputmethod.latin
  888   25728K   25724K    5774K    3668K  zygote
  977   24100K   24096K    5667K    4340K  android.process.acore
...
   59     336K     332K      99K      92K  /system/bin/installd
   60     396K     392K      93K      84K  /system/bin/keystore
   51     280K     276K      74K      68K  /system/bin/servicemanager
   54     256K     252K      69K      64K  /system/bin/debuggerd

在这里, VssRss列基本上是噪声(这些是一个进程的直接地址空间和RAM使用情况,如果在整个进程中累计RAM使用量,则会得到一个可笑的大数目)。

Pss就像我们以前见过的一样,而UssPriv Dirty

有趣的事情在这里注意: PssUss稍微(或稍多)不同于我们在meminfo看到的。 这是为什么? procrank使用不同的内核机制来收集其数据,而不是meminfo ,它们给出的结果稍有不同。 这是为什么? 老实说我没有线索。 我相信procrank可能是更准确的......但实际上,这只是procrank :“记下你用盐粒得到的任何记忆信息,通常是一颗非常大的粒。”

最后,命令adb shell cat /proc/meminfo给出系统总体内存使用情况的摘要。 这里有很多数据,只有前几个数字值得讨论(而其余的数据只有少数人能够理解,而我对少数人的问题通常会导致相互矛盾的解释):

MemTotal:         395144 kB
MemFree:          184936 kB
Buffers:             880 kB
Cached:            84104 kB
SwapCached:            0 kB

MemTotal是内核和用户空间可用的内存总量(通常小于设备的实际物理RAM,因为无线电,DMA缓冲区等需要某些RAM)。

MemFree是根本没有使用的RAM数量。 你在这里看到的数字非常高, 通常在Android系统上,这只有几MB,因为我们尝试使用可用内存来保持进程运行

Cached是用于文件系统缓存和其他类似内容的RAM。 典型的系统需要20MB左右,以避免陷入恶劣的寻呼状态; Android内存不足杀手会针对特定系统进行调整,以确保后台进程在被缓存的RAM消耗太多而导致进行此类分页之前被终止。


是的,您可以通过编程获得内存信息并决定是否进行内存密集型工作。

通过调用以下方式获取VM堆大小:

Runtime.getRuntime().totalMemory();

通过调用以下方式获取分配的VM内存:

Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

通过调用以下方式获取VM堆大小限制:

Runtime.getRuntime().maxMemory()

通过调用以下方式获取本地分配的内存:

Debug.getNativeHeapAllocatedSize();

我创建了一个应用程序来计算OutOfMemoryError行为并监视内存使用情况。

https://play.google.com/store/apps/details?id=net.coocood.oomresearch

您可以通过https://github.com/coocood/oom-research获取源代码


这是一项正在进行的工作,但这是我不明白的:

ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);

Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "n" );
Log.i(TAG, " memoryInfo.lowMemory " + memoryInfo.lowMemory + "n" );
Log.i(TAG, " memoryInfo.threshold " + memoryInfo.threshold + "n" );

List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();

Map<Integer, String> pidMap = new TreeMap<Integer, String>();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses)
{
    pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
}

Collection<Integer> keys = pidMap.keySet();

for(int key : keys)
{
    int pids[] = new int[1];
    pids[0] = key;
    android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
    for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
    {
        Log.i(TAG, String.format("** MEMINFO in pid %d [%s] **n",pids[0],pidMap.get(pids[0])));
        Log.i(TAG, " pidMemoryInfo.getTotalPrivateDirty(): " + pidMemoryInfo.getTotalPrivateDirty() + "n");
        Log.i(TAG, " pidMemoryInfo.getTotalPss(): " + pidMemoryInfo.getTotalPss() + "n");
        Log.i(TAG, " pidMemoryInfo.getTotalSharedDirty(): " + pidMemoryInfo.getTotalSharedDirty() + "n");
    }
}

为什么不将PID映射到activityManager.getProcessMemoryInfo()中的结果? 很明显,你想让结果数据有意义,所以为什么谷歌很难将结果关联起来呢? 如果我想处理整个内存使用情况,当前系统甚至不能正常工作,因为返回的结果是一个android.os.Debug.MemoryInfo对象数组,但是这些对象都没有告诉你它们与哪些pid关联。 如果你只是传入所有pid的数组,你将无法理解结果。 据我了解这是使用,它使一次传入多个pid没有意义,然后如果是这样,为什么要使activityManager.getProcessMemoryInfo()只接受一个int数组?

链接地址: http://www.djcxy.com/p/14009.html

上一篇: How do I discover memory usage of my application in Android?

下一篇: Why would you ever want to allocate memory on the heap rather than the stack?