$RodHat_
Syscall reference · Memory

madvise(2)

Advise the kernel how a memory range will be used: free it, page it out, exclude it from dumps.

Since
4.4BSDcheck your kernel →
glibc
unknown
System
Linux
Man page
madvise(2)

Synopsis

#include <sys/mman.h>

int madvise(void addr[size], size_t size, int advice);

Rod's take

Your service shows 7 GB RSS, gets OOM-killed, comes back at 800 MB, and somebody files a memory leak ticket. Wrong ticket. Allocators like jemalloc hand freed memory back with MADV_FREE, which lets the kernel reclaim those pages lazily, whenever it gets around to it, and until then they sit in your RSS like ghosts. MADV_DONTNEED drops them on the spot and charges you a page fault on reuse. MADV_FREE is the right call for throughput and a liar for monitoring. Read LazyFree out of smaps_rollup, subtract it, and stop paging people over phantom memory.

Flags and arguments that matter

NameWhat it does
MADV_DONTNEEDDrop the pages now: RSS falls immediately; next touch gets zero-fill (private anon) or file contents.
MADV_FREELinux 4.5Kernel may free the pages lazily under memory pressure; a write before then cancels the free. Private anon only.
MADV_DONTDUMPLinux 3.4Exclude the range from core dumps; overrides /proc/pid/coredump_filter.
MADV_DODUMPLinux 3.4Undo an earlier MADV_DONTDUMP.
MADV_DONTFORKLinux 2.6.16Don't make the range available to the child after fork(2).
MADV_WIPEONFORKLinux 4.14Child sees zero-filled memory in this range after fork; cleared on execve. Private anon only.
MADV_COLDLinux 5.4Deactivate the pages so they're likelier reclaim targets. Nondestructive.
MADV_PAGEOUTLinux 5.4Reclaim the pages now: anon goes to swap, dirty file pages get written back.
MADV_HUGEPAGELinux 2.6.38Enable transparent huge pages for the range.
MADV_POPULATE_WRITELinux 5.14Prefault page tables writable, as if writing to each page, without actually writing.

Errors you will actually hit

errnoMeaning
EINVALaddr not page-aligned, invalid advice, or advice not allowed on this mapping type (e.g. MADV_FREE on shared).
ENOMEMPart of the range isn't mapped; Linux applies the advice to the rest and still returns this.
EAGAINA kernel resource was temporarily unavailable.
EPERMMADV_HWPOISON without CAP_SYS_ADMIN.
EACCESMADV_REMOVE on a range that isn't a shared writable mapping.

Example

# RSS minus MADV_FREE pages the kernel can take back anytime
pid=$(pgrep -n "${1:?usage: $0 <process-name>}")
awk '
  /^Rss:/      { rss  = $2 }
  /^LazyFree:/ { lazy = $2 }
  END { printf "rss=%d kB  lazy=%d kB  committed=%d kB\n", rss, lazy, rss-lazy }
' /proc/$pid/smaps_rollup

# force jemalloc back to immediate MADV_DONTNEED for an honest RSS
MALLOC_CONF="dirty_decay_ms:0,muzzy_decay_ms:0" ./your-service

Trimmed from the full walkthrough in MADV_FREE and the RSS number that's lying to you.

BSD equivalent

FreeBSD: madvise(2) (4.4BSD) with MADV_FREE and MADV_NOCORE; minherit(2) INHERIT_ZERO for wipe-on-fork. OpenBSD: madvise(2) (since OpenBSD 2.7).

The long version, from the console

Sources

  1. madvise(2), man7.org
  2. madvise(2), FreeBSD
  3. madvise(2), OpenBSD

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.