Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Notes taken while looking into memory issues on low-RAM devices

Android Memory Management

Android has a unique memory management model. Below, are the notes taken while we try to understand it thoroughly.

Activity Manager

Overview

The ActivityManager, among other things, is responsible for making sure that apps that are most important to the user and/or essential remain active. It does this by dynamically assigning values that roughly indicate the app's importance. When memory gets low these values are used to find the apps that need to be "trimmed." The memory from these "trimmed" apps is freed, making more available for the more important apps.

How it works

As mentioned above, apps are dynamically ranked into importance categories, called adjustments, by the ActivityManager. The adjustments are defined in the ProcessList.java file and include the following:

Adjustments

Note: A lower value has higher priority. This list is ordered from lowest to highest priority. Descriptions are from the inline code comments.

 HIDDEN_APP_MAX_ADJ (15)::
  This is a process only hosting activities that are not visible, so it can be killed without any disruption.
 HIDDEN_APP_MIN_ADJ (9)::
  The bottom range of values fitting the above description.
 SERVICE_B_ADJ (8)::
  The B list of SERVICE_ADJ -- these are the old and decrepit services that aren't as shiny and interesting as the ones in the A list.
 PREVIOUS_APP_ADJ (7)::
  This is the process of the previous application that the user was in. This process is kept above other things, because it is very common to switch back to the previous app.  This is important both for recent task switch (toggling between the two top recent apps) as well as normal and then pressing back to return to e-mail.
 HOME_APP_ADJ (6)::
  This is a process holding the home application -- we want to try avoiding killing it, even if it would normally be in the background, because the user interacts with it so much.
 SERVICE_ADJ (5)::
  This is a process holding an application service -- killing it will not have much of an impact as far as the user is concerned.
 BACKUP_APP_ADJ (4)::
  This is a process currently hosting a backup operation.  Killing it is not entirely fatal but is generally a bad idea.
 HEAVY_WEIGHT_APP_ADJ (3)::
  This is a process with a heavy-weight application.  It is in the background, but we want to try to avoid killing it.  Value set in system/rootdir/init.rc on startup.
 PERCEPTIBLE_APP_ADJ (2)::
  This is a process only hosting components that are perceptible to the user, and we really want to avoid killing them, but they are not immediately visible. An example is background music playback.
 VISIBLE_APP_ADJ (1)::
  This is a process only hosting activities that are visible to the user, so we'd prefer they don't disappear.
 FOREGROUND_APP_ADJ (0)::
  This is the process running the current foreground app.  We'd really rather not kill it!
 PERSISTENT_PROC_ADJ (-12)::
  This is a system persistent process, such as telephony.  Definitely don't want to kill it, but doing so is not completely fatal.
 SYSTEM_ADJ (-16)::
  The system process runs at the default adjustment.

Notice that the lowest two adjustments have a MAX and MIN values. This is because there are is also a more fine-grained ranking system that is internal to ActivityManagerService. For example, empty apps are those apps that are hidden but no longer have an activity associated with it.

Low Memory Killer

The adjustments are used by the Linux kernel to determine which process should be terminated. The kernel knows about these adjustments via the sysfs interface to lowmemorykiller. The lowmemorykiller is a kernel module that moves the roll of managing out of memory (OOM) issues to the user space. It does this by allowing the user-space to maintain a list of adjustments and a corresponding list of thresholds (units are in memory pages - usually 4K) at which point processes with these adjustments should be killed.

While the management is moved to user-space, the actually killing of process is done by the lowmemorykiller. The lowmemorykiller's schrinker is registered and with the kernel run by the kwapd kernel thread.

The interfaces for lowmemorykiller can be found in the /sys/module/lowmemorykiller/parameters/ directory.

 adj::
  Comma separated list of adjustments. Example: ```0,1,2,4,10,15```
 cost::
  This used to set the value of lowmem_shrinker.seeks. This value determines how many slab objects shrinker() should scan and try to reclaim. Default ```32```
 debug_level::
  Debug level. Can be set to a range of 0-5, with 5 being most verbose.
 minfree::
  Comma separated list of page table thresholds. Example: ```1024,2304,4096,9216,12544,16384```

Valid values for the adjustments are defined in oom.h

/*
 * /proc/<pid>/oom_adj is deprecated, see
 * Documentation/feature-removal-schedule.txt.
 *
 * /proc/<pid>/oom_adj set to -17 protects from the oom-killer
 */
#define OOM_DISABLE (-17)
/* inclusive */
#define OOM_ADJUST_MIN (-16)
#define OOM_ADJUST_MAX 15

/*
 * /proc/<pid>/oom_score_adj set to OOM_SCORE_ADJ_MIN disables oom killing for
 * pid.
 */
#define OOM_SCORE_ADJ_MIN	(-1000)
#define OOM_SCORE_ADJ_MAX	1000

Note: Although oom_adj is deprecated in upstream kernels, it's still supported and it's what Android uses.

The challenge is to find a set of values for the lowmemorykiller that all the system to kill off process when memory gets tight in a way that the user won't notice or at the least not be bothered by.

The oom_adj value is continuously updated by !ActivityManagerService. The values are finally written to /proc/{pid}/oom_adj in the android_os_Process_setOomAdj method of android_util_Process.cpp which is invoked by !ActivityManagerService's updateOomAdjLocked method.

Application memory management

Applications have a couple methods they can use to proactively help when memory pressure is increasing. The first line of defense is to override and handle [http://developer.android.com/reference/android/content/ComponentCallbacks2.html#onTrimMemory(int) onTrimMemory]. onTrimMemory takes a parameter which indicates the current memory pressure. It's the most granular way to manage memory. For a description of the see the [http://developer.android.com/reference/android/content/ComponentCallbacks2.htm ComponentCallbacks2 class overview]. The last line of defense is [http://developer.android.com/reference/android/app/Activity.html#onLowMemory() onLowMemory]. This method takes no arguments and is called only when the background LRU list is empty, meaning all trimming efforts have been exhausted.

In order for these to be called !ActivityManager keeps track of processes via instances of the !ProcessRecord class. A !ProcessRecord object keeps track of all aspects of a running process. The actual process is accessible via the !ProcessRecord's thread member. The thread implements !IApplicationThread whose contract includes methods for scheduling onLowMemory (scheduleLowMemory) and onTrimMemory (scheduleTrimMemory).

Dalvik

Properties

The following properties can control how Dalvik manages its heap.

Property Default Variable in code Notes
dalvik.vm.heapsize 16m !DvmGlobals.heapMaximumSize This is the max heap size when an app sets the largeHeap property to true in the AndroidManifest.xml.
dalvik.vm.heapgrowthlimit dalvik.vm.heapsize !DvmGlobals.heapgGrowthLimit This the typical max heap size, meaning when the largeHeap property is not true. This should typically be no more that half the heapsize value.
dalvik.vm.heaptargetutilization 0.50 !DvmGlobals.heaptargetUtilization The ideal ratio of live to free memory. Is clamped to have a value between 0.2 and 0.8.
dalvik.vm.heapmaxfree 2m !DvmGlobals.heapMaxFree Forces the free memory to never be larger than the given value.
dalvik.vm.heapminfree dalvik.vm.heapmaxfree / 4 !DvmGlobals.heapMinFree Forces the free memory to never be smaller than the given value.
dalvik.vm.heapstartingsize 2m !DvmGlobals.heapStartingSize The initial starting size of the heap from which it will grow to growthLimit.

Note: Values are in bytes, can be given single-letter multipliers (k, m, g), and must be divisible by 1024.

GC Types

You'll often see Dalvik output of the following form.

D/dalvikvm(  193): GC_EXPLICIT freed 39K, 66% free 2349K/6788K, paused 24ms+8ms, total 129ms

For the most part this is self-explanatory. However, the GC_EXPLICIT, in the instance is telling us what type of GC is being done. There are 4 types of GC defined in Heap.cpp.

  • GC_FOR_ALLOC Not enough space for an "ordinary" Object to be allocated.
  • GC_CONCURRENT Automatic GC triggered by exceeding a heap occupancy threshold.
  • GC_EXPLICIT Explicit GC via Runtime.gc(), VMRuntime.gc(), or SIGUSR1.
  • GC_BEFORE_OOM Final attempt to reclaim memory before throwing an OOM.

Save the last type, all of these should be expected to happen during normal operation.

Gathering memory information

Android and Linux provide us several ways to monitor the state of process and memory management on a running system.

procfs

The procfs directory /proc/[pid]/ has a number of pseudo files that can be used for viewing process state. See [http://man7.org/linux/man-pages/man5/proc.5.html the procfs man page] for a detailed list. Of most interest to us is /proc/[pid]/oom_adj. This file is where we can see which adjustment level the !ActivityManagerService has assigned to a process. The values correspond with the levels shown above and set in !ProcessList.

Commands

The dumpsys command can tell us almost anything we want to know about the system and a particular time. The most interesting for us are the dumpsys meminfo & dumpsys activity oom. These commands tell us and applications adjustment state, current memory usage, it's garbage collecting state and much more.

dumpsys meminfo

An example of the output from dumpsys meminfo follows.

    18642 kB: system (pid 451)
    18349 kB: com.android.launcher (pid 3106)
    14552 kB: android.process.acore (pid 3133)
     9884 kB: com.android.systemui (pid 1791)
     9498 kB: com.google.process.gapps (pid 735)
     7078 kB: com.google.process.location (pid 667)
     5623 kB: com.android.inputmethod.latin (pid 646)
     5566 kB: com.google.android.syncadapters.calendar (pid 3270)
     5475 kB: com.google.android.apps.genie.geniewidget (pid 3185)
     4940 kB: com.google.android.gsf.login (pid 3254)
     4362 kB: com.android.browser (pid 3359)
     4095 kB: com.android.phone (pid 689)
     3898 kB: com.android.calendar (pid 3305)
     3691 kB: com.android.providers.calendar (pid 3286)
     3360 kB: com.cyanogenmod.lockclock (pid 3327)
     2810 kB: redacted (pid 3117)
     2599 kB: com.android.location.fused (pid 676)
     2319 kB: com.android.smspush (pid 795)

Total PSS by OOM adjustment:
    18642 kB: System
               18642 kB: system (pid 451)
    13979 kB: Persistent
                9884 kB: com.android.systemui (pid 1791)
                4095 kB: com.android.phone (pid 689)
    18349 kB: Foreground
               18349 kB: com.android.launcher (pid 3106)
    18895 kB: Visible
                9498 kB: com.google.process.gapps (pid 735)
                7078 kB: com.google.process.location (pid 667)
                2319 kB: com.android.smspush (pid 795)
     8222 kB: Perceptible
                5623 kB: com.android.inputmethod.latin (pid 646)
                2599 kB: com.android.location.fused (pid 676)
     2810 kB: A Services
                2810 kB: redacted (pid 3117)
    45844 kB: Background
               14552 kB: android.process.acore (pid 3133)
                5566 kB: com.google.android.syncadapters.calendar (pid 3270)
                5475 kB: com.google.android.apps.genie.geniewidget (pid 3185)
                4940 kB: com.google.android.gsf.login (pid 3254)
                4362 kB: com.android.browser (pid 3359)
                3898 kB: com.android.calendar (pid 3305)
                3691 kB: com.android.providers.calendar (pid 3286)
                3360 kB: com.cyanogenmod.lockclock (pid 3327)

Total PSS by category:
    60792 kB: Dalvik
    32872 kB: Unknown
    14517 kB: .dex mmap
    12536 kB: .so mmap
     4856 kB: .apk mmap
      700 kB: Other mmap
      256 kB: Native
       76 kB: Ashmem
       72 kB: Other dev
       44 kB: .ttf mmap
       16 kB: Cursor
        4 kB: .jar mmap

Total PSS: 126741 kB
      KSM: 6672 kB saved from shared 1128 kB
           24552 kB unshared; 102936 kB volatile

The output from this command is pretty straight forward so I won't describe it detail.

If you provide dumpsys meminfo with a package name, such as org.mozilla.firefox, you get more detailed output about that process.

root@oc:/ # dumpsys meminfo org.mozilla.firefox                                
Applications Memory Usage (kB):
Uptime: 4117434 Realtime: 8929976

** MEMINFO in pid 3400 [org.mozilla.firefox] **
                         Shared  Private     Heap     Heap     Heap
                   Pss    Dirty    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------
       Native       16        8       16     4492     4052      439
       Dalvik    12056     4764    11624    10912     6252     4660
       Cursor        0        0        0                           
       Ashmem    14620       24    14608                           
    Other dev        4       20        0                           
     .so mmap     3151     1876      460                           
    .jar mmap        0        0        0                           
    .apk mmap      766        0        0                           
    .ttf mmap       32        0        0                           
    .dex mmap     5641        0        0                           
   Other mmap      387       16       84                           
      Unknown    74698      428    74672                           
        TOTAL   111371     7136   101464    15404    10304     5099
 
 Objects
               Views:      107         ViewRootImpl:        1
         AppContexts:        3           Activities:        1
              Assets:        2        AssetManagers:        2
       Local Binders:       23        Proxy Binders:       19
    Death Recipients:        0
     OpenSSL Sockets:        0
 
 SQL
         MEMORY_USED:      540
  PAGECACHE_OVERFLOW:      214          MALLOC_SIZE:      154
 
 DATABASES
      pgsz     dbsz   Lookaside(b)          cache  Dbname
         4       72             48        10/26/6  /data/data/org.mozilla.firefox/files/mozilla/7bx4gz6c.default/health.db
         4      880            172       35/51/14  /data/data/org.mozilla.firefox/files/mozilla/7bx4gz6c.default/browser.db
         4      880            108        32/23/9  /data/data/org.mozilla.firefox/files/mozilla/7bx4gz6c.default/browser.db (2)
 
 Asset Allocations
    zip:/data/app/org.mozilla.firefox-1.apk:/resources.arsc: 531K

For an explanation of this see Dianne Hackborn's StackOverflow description. Dianne is a core Android engineer, responsible for important stuff like Binder.

dumpsys activity oom

An example of the output from dumpsys activity oom follows.

  OOM levels:
    SYSTEM_ADJ: -16
    PERSISTENT_PROC_ADJ: -12
    FOREGROUND_APP_ADJ: 0
    VISIBLE_APP_ADJ: 1
    PERCEPTIBLE_APP_ADJ: 2
    HEAVY_WEIGHT_APP_ADJ: 3
    BACKUP_APP_ADJ: 4
    SERVICE_ADJ: 5
    HOME_APP_ADJ: 6
    PREVIOUS_APP_ADJ: 7
    SERVICE_B_ADJ: 8
    HIDDEN_APP_MIN_ADJ: 10
    HIDDEN_APP_MAX_ADJ: 15
 
  Process OOM control:
    PERS # 7: adj=sys  /F  trm=15 451:system/1000 (fixed)
        oom: max=-16 hidden=10 client=10 empty=10 curRaw=-16 setRaw=-16 cur=-16 set=-16
        keeping=true hidden=false empty=false hasAboveClient=false
    PERS #10: adj=pers /F  trm=15 689:com.android.phone/1001 (fixed)
        oom: max=-12 hidden=10 client=10 empty=10 curRaw=-12 setRaw=-12 cur=-12 set=-12
        keeping=true hidden=false empty=false hasAboveClient=false
    PERS # 3: adj=pers /F  trm=15 1791:com.android.systemui/u0a10030 (fixed)
        oom: max=-12 hidden=10 client=10 empty=10 curRaw=-12 setRaw=-12 cur=-12 set=-12
        keeping=true hidden=false empty=false hasAboveClient=false
    Proc # 0: adj=fore /FA trm=15 3106:com.android.launcher/u0a10022 (top-activity)
        oom: max=15 hidden=10 client=10 empty=10 curRaw=0 setRaw=0 cur=0 set=0
        keeping=true hidden=false empty=false hasAboveClient=false
    Proc # 9: adj=vis  /F  trm=15 795:com.android.smspush/u0a10032 (service)
        com.android.smspush/.WapPushManager<=Proc{689:com.android.phone/1001}
        oom: max=15 hidden=10 client=10 empty=10 curRaw=1 setRaw=1 cur=1 set=1
        keeping=true hidden=false empty=true hasAboveClient=false
    Proc # 8: adj=vis  /B  trm=15 735:com.google.process.gapps/u0a10033 (provider)
        com.google.android.gsf/.settings.GoogleSettingsProvider<=Proc{667:com.google.process.location/u0a10033}
        oom: max=15 hidden=10 client=10 empty=10 curRaw=1 setRaw=1 cur=1 set=1
        keeping=true hidden=false empty=true hasAboveClient=false
    Proc # 6: adj=vis  /B  trm=15 667:com.google.process.location/u0a10033 (service)
        com.google.android.location/.NetworkLocationService<=Proc{451:system/1000}
        oom: max=15 hidden=10 client=10 empty=10 curRaw=1 setRaw=1 cur=1 set=1
        keeping=true hidden=false empty=true hasAboveClient=false
    Proc # 1: adj=vis  /B  trm=15 3133:android.process.acore/u0a10001 (provider)
        com.android.providers.contacts/.ContactsProvider2<=Proc{735:com.google.process.gapps/u0a10033}
        oom: max=15 hidden=10 client=10 empty=10 curRaw=1 setRaw=1 cur=1 set=1
        keeping=true hidden=false empty=true hasAboveClient=false
    Proc # 5: adj=prcp /F  trm=15 646:com.android.inputmethod.latin/u0a10021 (service)
        com.android.inputmethod.latin/.LatinIME<=Proc{451:system/1000}
        oom: max=15 hidden=10 client=10 empty=10 curRaw=2 setRaw=2 cur=2 set=2
        keeping=true hidden=false empty=true hasAboveClient=false
    Proc # 4: adj=prcp /B  trm=15 676:com.android.location.fused/u0a10018 (service)
        com.android.location.fused/.FusedLocationService<=Proc{451:system/1000}
        oom: max=15 hidden=10 client=10 empty=10 curRaw=2 setRaw=2 cur=2 set=2
        keeping=true hidden=false empty=true hasAboveClient=false
    Proc # 2: adj=svc  /B  trm=15 3117:redacted/u0a10014 (started-services)
        oom: max=15 hidden=10 client=10 empty=10 curRaw=5 setRaw=5 cur=5 set=5
        keeping=true hidden=false empty=true hasAboveClient=false
 
  Processes that are waiting to GC:
    Process ProcessRecord{422a4260 735:com.google.process.gapps/u0a10033}
      lowMem=true, last gced=3110616 ms ago, last lowMem=18198 ms ago
    Process ProcessRecord{422f13b0 451:system/1000}
      lowMem=true, last gced=3110616 ms ago, last lowMem=18198 ms ago
    Process ProcessRecord{4247c388 667:com.google.process.location/u0a10033}
      lowMem=true, last gced=3110616 ms ago, last lowMem=18198 ms ago
    Process ProcessRecord{4231a630 646:com.android.inputmethod.latin/u0a10021}
      lowMem=true, last gced=3110616 ms ago, last lowMem=18198 ms ago
    Process ProcessRecord{4250cfe0 676:com.android.location.fused/u0a10018}
      lowMem=true, last gced=3110616 ms ago, last lowMem=18198 ms ago
    Process ProcessRecord{422f2dd8 1791:com.android.systemui/u0a10030}
      lowMem=true, last gced=3110616 ms ago, last lowMem=18198 ms ago

  mHomeProcess: ProcessRecord{422e4ce8 3106:com.android.launcher/u0a10022}
  mPreviousProcess: null

The "Process OOM control" section of this output is a list of process sorted by their current adjustment values with a lot of other useful information, some of which needs further explanation.

Interpreting the output

Let's take a look at the following excerpt.

Proc # 8: adj=vis  /B  trm=15 735:com.google.process.gapps/u0a10033 (provider)
        com.google.android.gsf/.settings.GoogleSettingsProvider<=Proc{667:com.google.process.location/u0a10033}
        oom: max=15 hidden=10 client=10 empty=10 curRaw=1 setRaw=1 cur=1 set=1
        keeping=true hidden=false empty=true hasAboveClient=false

The table below explains each field, provides a description and notes other possible values or value ranges.

First Line
field type range/format Interpretation
Proc string PERS, Proc Process labeled with "Proc" are normal process that fall under the domain of the lowmemorykiller. Those labeled "PRES" are persistent process and are generally go untouched by the lowmememorykiller.
# 8 int 0 to (!NumberOfProcessRecords - 1) The position of the process in the Least Recently Used (LRU) process list.
adj int Abbreviation of the adjustments from above. This is the current adjustment level of the app.
/B string /{B,F}{ ,A,S} B or F tells us if this is a background or foreground process, respectively. The optional A and S indicate whether this processes is running any foreground activities or services, respectively.
trm int These values corrospond to trim levels defined in [http://developer.android.com/reference/android/content/ComponentCallbacks2.html ComponentCallbacks2] Last selected memory trimming level.
735:com.google.process.gapps/u0a10033 string pid:process_name:a{userId}u{appId} or pid:process_name:uid
(provider) string (adjustmentType) This is the primary factor contributing to calculate the oom_adj value. The logic for determining this value is in !ActivityManagerService's computeOomAdjLocked method.
2nd line

This line is printed when there is a either a source or target for the process. The format is source<#target.

  source::
   An option dependent object
  target::
   The target component impacting the OOM adjustment. This impact is mostly determined by the flags past to Context.bindService().
3rd line

These levels are all adjustment levels and most be in that range (-17 - 15).

field type Interpretation
max int Maximum OOM adjustment for this process.
hidden int If hidden, this is the adjustment to use
client int If empty but hidden client, this is the adjustment to use
empty int If empty, this is the adjustment to use
curRaw int Current OOM unlimited adjustment for this process
setRaw int Last set OOM unlimited adjustment for this process
cur int Current OOM adjustment for this process
set int Last set OOM adjustment for this proces
4th line
field type range/format Interpretation
keeping boolean N/A Actively running code so it needs to be kept around and not killed.
hidden boolean N/A Whether this is a hidden process.
empty boolean N/A Whether this is an empty background process.
hasAboveClient boolean N/A Whether the process is is bound to a service that it considers more important than itself. The is done by using the BIND_ABOVE_CLIENT flag when calling bindService. This used when one would rather the process die before the service.

procrank

procrank shows system processes ranked by their memory usage. An example of its output follows.

  PID      Vss      Rss      Pss      Uss  cmdline
  451   29508K   29464K   18528K   17384K  system_server
 3106   83228K   33624K   18489K   16056K  com.android.launcher
 3133   28804K   28696K   14630K   13032K  android.process.acore
 1791   33844K   20328K    9935K    8648K  com.android.systemui
  735   20940K   20864K    9507K    8060K  com.google.process.gapps
  667   16592K   16508K    7147K    6532K  com.google.process.location
  646   17136K   14508K    5688K    5068K  com.android.inputmethod.latin
 3270   19464K   19372K    5653K    3920K  com.google.android.syncadapters.calendar
 3185   19436K   19340K    5574K    4324K  com.google.android.apps.genie.geniewidget
 3254   18092K   17980K    5026K    3896K  com.google.android.gsf.login
 3359   17956K   17860K    4443K    3284K  com.android.browser
  689   12664K   12568K    4160K    3636K  com.android.phone
 3305   17360K   17260K    3981K    2864K  com.android.calendar
 3286   17340K   17240K    3770K    2668K  com.android.providers.calendar
  218    3992K    3992K    3745K    3656K  /system/bin/mediaserver
 3327   16304K   16204K    3229K    2144K  com.cyanogenmod.lockclock
 3117   15684K   15580K    2892K    1928K  redacted
  676   11996K   11888K    2674K    2024K  com.android.location.fused
  795   10872K   10764K    2386K    1788K  com.android.smspush
  216   11392K   11244K    1941K    1280K  zygote
  214    1964K    1964K    1915K    1908K  /system/bin/debuggerd
  215   31148K    1772K    1264K    1108K  /system/bin/surfaceflinger
 3388    1252K    1252K    1075K    1024K  procrank
  217     700K     700K     673K     672K  /system/bin/drmserver
  213     820K     820K     573K     548K  /system/bin/netd
  211     376K     376K     276K     264K  /system/bin/vold
  220     380K     380K     266K     260K  /system/bin/keystore
  221     264K     264K     260K     260K  /bin/busybox
  474     324K     324K     235K     232K  /system/bin/sh
  222     236K     236K     216K     216K  /sbin/adbd
  176     240K     240K     195K     180K  /sbin/nbd-client
  162     240K     240K     195K     180K  /sbin/nbd-client
  168     240K     240K     195K     180K  /sbin/nbd-client
  184     240K     240K     195K     180K  /sbin/nbd-client
  212     328K     328K     192K     180K  /system/bin/logcat
    1     248K     248K     180K     132K  /init
  207     204K     204K     140K     136K  /system/bin/sdcard
   62     172K     172K     120K      72K  /sbin/ueventd
  219     144K     144K     115K     112K  /system/bin/installd
  210     132K     132K     101K     100K  /system/bin/servicemanager
                          ------   ------  ------
                         141794K  120136K  TOTAL

RAM: 373148K total, 90428K free, 17512K buffers, 59908K cached, 2516K shmem, 12532K slab

Here we see that procrank gives us more, but uncategorized, information about a processes memory usage. Additionally, the last line gives a system wide view of memory usage.

Official Documentation

Since we started this wiki page, Google has added some official documentation regarding memory management.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.