Mac Performance Guide

Check memory usage per process from the Mac terminal

Short answer

Run top -l 1 -o mem -n 10 -stats pid,command,mem,cmprs,purg. The MEM column is each process's physical memory footprint, the same number Activity Monitor's Memory column shows. ps -eo rss gives a different number, RSS, which counts shared pages that every process maps and ignores memory macOS has compressed, so it reads high for some processes and low for others. For the whole Mac use vm_stat, memory_pressure and sysctl vm.swapusage.

top: processes by footprint

Memory, unlike CPU, is a snapshot rather than a rate, so one sample is enough:

top -l 1 -o mem -n 8 -stats pid,command,mem,cmprs,purg | tail -9
PID    COMMAND          MEM   CMPRS PURG
32186  rustrover        2949M 808M  0B
3678   datagrip         1844M 266M  67M
3665   ghostty          1814M 502M  4608K
606    WindowServer     1806M 588M  24M
3680   zoom.us          1494M 540M  112K
34614  Postman Helper ( 1078M 928M  0B
3667   Messages         793M  510M  0B
21751  Google Chrome He 775M  123M  0B

man top defines MEM as the "physical memory footprint of the process": the pages it is responsible for, including the ones macOS has compressed (CMPRS) and, on Apple Silicon, the GPU memory it owns, since CPU and GPU share one pool. PURG is purgeable memory the process has said macOS may drop. Leave off -l 1 to watch it live, sorted by memory, and top -pid 32186 -stats pid,command,mem,cmprs follows one process. The process name is cut to 16 characters; ps -p 34614 -o command= shows the full one.

ps: RSS, and why it disagrees

ps can print each process's resident set size in kilobytes, with the full path, which top cannot:

ps -eo rss,comm | sort -rn | head -5
2794208 /Applications/RustRover.app/Contents/MacOS/rustrover
1634192 /Applications/DataGrip.app/Contents/MacOS/datagrip
821232 /Applications/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Versions/154.0.8037.57/Helpers/Google Chrome Helper (Renderer).app/Contents/MacOS/Google Chrome Helper (Renderer)
758576 /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

RSS is every page currently resident in RAM that the process has mapped. That is a different question from footprint, in two ways:

So RSS is fine for "is this process growing?" over time, and poor for comparing processes or adding them up. ps -m claims to sort by memory but does not order by RSS on current macOS; pipe through sort as above.

footprint: one process in detail

macOS ships a footprint command that explains where a process's footprint comes from. It takes a PID or -p with a name:

footprint -p rustrover
======================================================================
rustrover [32186]: 64-bit    Footprint: 2949 MB (16384 bytes per page)
======================================================================

  Dirty      Clean  Reclaimable    Regions    Category
    ---        ---          ---        ---        ---
2218 MB        0 B          0 B       8005    untagged (VM_ALLOCATE)
 605 MB        0 B          0 B        178    MALLOC_SMALL
  36 MB        0 B          0 B         83    Owned physical footprint (unmapped) (graphics)
  32 MB        0 B          0 B         39    IOSurface

The headline matches top. The categories tell you whether the memory is the heap (MALLOC), a runtime's own regions (the JVM's heap shows up as untagged VM_ALLOCATE), graphics surfaces, or stacks. footprint --swapped adds a column for how much is compressed or swapped. vmmap --summary 32186 | grep footprint gives the same total plus the peak. Without sudo both work only for your own processes; footprint 606 for WindowServer answers "try as root?", the same rule that makes htop show 0% for root's processes.

The whole Mac: vm_stat, memory_pressure and swap

vm_stat
Mach Virtual Memory Statistics: (page size of 16384 bytes)
Pages free:                                    20072.
Pages active:                                1024159.
Pages inactive:                              1012134.
Pages wired down:                             373924.
File-backed pages:                            558928.
Anonymous pages:                             1488690.
Pages occupied by compressor:                 644091.

Everything is in pages; multiply by the page size on the first line (16 KB on Apple Silicon, 4 KB on Intel). Those lines map onto Activity Monitor's Memory tab on a 48 GB Mac like this:

Apple defines Memory Used as app memory plus wired plus compressed, about 38 GB here. top's header line said PhysMem: 47G used, 489M unused at the same moment because it counts cached files as used, and they are: macOS fills idle RAM with file cache it can drop instantly. That is why the two commands that report pressure matter more than any "used" number:

memory_pressure | tail -1; sysctl vm.swapusage kern.memorystatus_vm_pressure_level
System-wide memory free percentage: 66%
vm.swapusage: total = 8192.00M  used = 6684.31M  free = 1507.69M  (encrypted)
kern.memorystatus_vm_pressure_level: 1

66% free with 489 MB unused is not a contradiction: free here means reclaimable without hurting anything. Pressure level 1 is normal, 2 warning, 4 critical. Mac memory pressure yellow/red explains what to do when it is not 1, and High swap usage on Mac covers the swap line.

The easier way: GaugeMon

GaugeMon's Memory gauge sits in the menu bar; click it for app, wired, compressed and cached memory, swap, pressure, a chart of the last 10 minutes and the five largest processes by physical footprint, the same measure as top's MEM column and Activity Monitor. The Processes window sorts every process by Memory, and the optional helper fills in root's processes, which footprint and vmmap cannot read without sudo.

GaugeMon's Processes window with per-core meters and load average above a sortable table of processes
Download GaugeMon free trial Learn more

Related guides