Read a Process Memory Map with pmap
A process is eating memory and top will not tell you where, so pmap breaks its address space into something you can read. You will list mapped ranges, add resident and dirty columns, filter a range, show real file paths, and handle a PID that vanishes mid-check. Allow about ten minutes. You need the procps package and a shell; these examples only read process information and normally need no elevated privileges.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide was checked with procps version 2:4.0.4-4ubuntu3.3. Output shape varies with the process, kernel and installed libraries, so treat the layout of the output as the thing to check, not the exact addresses.
1. Choose a live process
For a quick look, use the shell's own PID. The shell expands $$ before pmap even starts, so the command does not depend on you guessing a process number:
$ pmap $$
000055... 192K r---- bash
000055... 956K r-x-- bash
00007f... 2988K r---- locale-archive
...
total 7752K
The first column is a virtual address. The size column is the mapped size in KiB, followed by permissions and a mapping name. The final total is the total mapped address space for this invocation. Anonymous mappings, shared libraries, a stack, and special kernel-provided mappings are all normal here, so do not be surprised by a long list.
To inspect another process, swap in a real PID. Find one without changing anything on the system:
$ pgrep -a -f 'YOUR-PROCESS-NAME'
1234 /usr/bin/YOUR-PROCESS-NAME --example
$ pmap 1234
Only inspect a process you are actually allowed to see. The kernel's own permissions can restrict access to another user's /proc/PID data. Running as root reveals more, but it still does not turn the map into a measurement of physical RAM.
2. Add resident and dirty memory columns
The default listing is good for layout, but it will not tell you how much of each mapping is actually resident. Add -x, or its long form --extended:
$ pmap -x $$
Address Kbytes RSS Dirty Mode Mapping
000055... 192 180 0 r---- bash
000055... 956 828 0 r-x-- bash
...
total 7752 4936 412
Kbytes is the mapped size, RSS is the resident set size, and Dirty is the dirty amount for that mapping. These answer different questions: a large mapped library or reserved region is not necessarily occupying the same amount of physical memory right now. The totals are a single snapshot, not a promise about what the process will keep holding.
Checkpoint
Rerun the command if you are comparing values over time. Do not treat one pmap -x result as a leak diagnosis; allocators, lazy loading and concurrent activity can all shift the map between two readings.
3. Show paths and device details when names are ambiguous
Normal output can identify a mapping by basename alone, which is not always enough. Use -p to show the full path for file-backed mappings:
$ pmap -p $$ | sed -n '1,6p'
1234: /bin/bash -c ...
000055... 192K r---- /usr/bin/bash
000055... 956K r-x-- /usr/bin/bash
Need the mapped file's device and offset too? Use -d instead. Its columns include Offset and Device, which can tell apart mappings that share a displayed name. Both are reporting choices: neither one touches the process or its mappings.
4. Narrow the report to an address range
Pass -A followed by one argument holding the low and high addresses, separated by a comma that is part of the argument itself:
$ pmap -A 0,ffffffff $$
total 0K
That range is deliberately narrow for a normal 64-bit process, so an empty result is the expected outcome, not evidence something is wrong. To get a useful range, run pmap $$ first, copy an address range from its output, and pass a lower and upper bound from that. Do not put a space after the comma. A range with no matches is a successful report, not proof the process has no memory.
5. Make scripts quieter and handle missing PIDs
Use -q when the header and footer are just noise in a pipeline. It keeps the mapping rows while dropping some of the surrounding lines:
$ pmap -q $$ | sed -n '1,3p'
000055... 192K r---- bash
000055... 956K r-x-- bash
000055... 212K r---- bash
A process can exit in the gap between you finding its PID and reading its map. The manual documents exit status 42 for when not all requested processes are found, and 1 for a general failure. Capture the status before another command overwrites it:
pmap "$PID" >/tmp/pmap.out 2>/tmp/pmap.err
status=$?
case "$status" in
0) sed -n '1,12p' /tmp/pmap.out ;;
42) printf '%s\n' 'The process was missing or ended during the check.' >&2; exit 42 ;;
*) cat /tmp/pmap.err >&2; exit "$status" ;;
esac
Replace $PID with a value your own script supplies, and never feed an untrusted string straight into a shell command. Those temporary files hold process mapping information, so remove them after review once you no longer need it:
$ rm -f /tmp/pmap.out /tmp/pmap.err
That cleanup is optional and irreversible. Do not run it until you have actually finished checking the reports.
6. Leave configuration alone unless you need it
This version also supports procps configuration options: -c reads the default configuration, -C FILE reads a specified file, -n creates a new default configuration, and -N FILE creates one at a specified path. None of the creation options accept a PID argument. They live in a separate world from inspecting a process, and can create or overwrite configuration state, so keep them out of an ordinary diagnostic command unless you have a genuine configuration task and a backup or new destination lined up.
For more detail, run man pmap. The installed manual is the authority for this machine, especially for the extra detail modes -X and -XX, whose output follows kernel-provided data and can change between systems.
Done means
- Found a live PID. You produced a normal
pmaplisting for it. - Read the extended columns. You used
-xwhen you needed mapped, resident and dirty figures. - Identified ambiguous mappings. You used
-por-dwhen a basename alone was not enough. - Formatted the address range correctly. You kept the low and high values for
-Ain one comma-separated argument. - Handled a missing process. Your script distinguishes exit status
42from a general failure. - Stayed read-only. You did not change process state or reach for elevated privileges without a specific reason.