The free
utility is used to display the amount of free and used memory in the system. Debian Stretch provides an upgraded package. Output format has changed, and available memory is calculated using a different method, so let’s see what we can do with these modifications at this moment.
The old behavior
Used procps-ng version.
$ free -V free from procps-ng 3.3.9
Standard output using the KiB unit.
$ free
total used free shared buffers cached Mem: 16358744 13444504 2914240 498912 189188 1973396 -/+ buffers/cache: 11281920 5076824 Swap: 15998972 252356 15746616
Standard output using the MiB unit.
$ free -m
total used free shared buffers cached Mem: 15975 13129 2845 487 184 1927 -/+ buffers/cache: 11017 4957 Swap: 15623 246 15377
The method used to calculate available memory depends directly on the proc filesystem: MemFree plus Buffers plus Cache fields read from /proc/meminfo
file. It does not consider the amount of reclaimable memory used by the kernel to cache data structures, page cache, and reserved pages.
[...] printf("%s\n", _(" total used free shared buffers cached")); printf("%-7s", _("Mem:")); printf(" %10s", scale_size(kb_main_total, flags, args)); printf(" %10s", scale_size(kb_main_used, flags, args)); printf(" %10s", scale_size(kb_main_free, flags, args)); printf(" %10s", scale_size(kb_main_shared, flags, args)); printf(" %10s", scale_size(kb_main_buffers, flags, args)); printf(" %10s", scale_size(kb_main_cached, flags, args)); printf("\n"); [...] if (!(flags & FREE_OLDFMT)) { unsigned KLONG buffers_plus_cached = kb_main_buffers + kb_main_cached; printf(_("-/+ buffers/cache:")); printf(" %10s", scale_size(kb_main_used - buffers_plus_cached, flags, args)); printf(" %10s", scale_size(kb_main_free + buffers_plus_cached, flags, args)); printf("\n"); } [...]
The new behavior
Used procps-ng version.
$ free -V free from procps-ng 3.3.10
Standard output using the KiB unit.
$ free
total used free shared buff/cache available Mem: 16358744 7324312 2914240 498912 6120192 4439720 Swap: 15998972 252356 15746616
Standard output using the MiB unit.
$ free -m
total used free shared buff/cache available Mem: 15975 7152 2845 487 5976 4335 Swap: 15623 246 15377
The method used to calculate available memory depends directly on the proc filesystem: MemAvailable field read from /proc/meminfo
file.
[...] if (flags & FREE_WIDE) { printf(_(" total used free shared buffers cache available")); } else { printf(_(" total used free shared buff/cache available")); } printf("\n"); printf("%-7s", _("Mem:")); printf(" %11s", scale_size(kb_main_total, flags, args)); printf(" %11s", scale_size(kb_main_used, flags, args)); printf(" %11s", scale_size(kb_main_free, flags, args)); printf(" %11s", scale_size(kb_main_shared, flags, args)); if (flags & FREE_WIDE) { printf(" %11s", scale_size(kb_main_buffers, flags, args)); printf(" %11s", scale_size(kb_main_cached, flags, args)); } else { printf(" %11s", scale_size(kb_main_buffers+kb_main_cached, flags, args)); } printf(" %11s", scale_size(kb_main_available, flags, args)); printf("\n"); [...]
Excerpt from the free
manual page.
available Estimation of how much memory is available for starting new applications, without swapping. Unlike the data provided by the cache or free fields, this field takes into account page cache and also that not all reclaimable memory slabs will be reclaimed due to items being in use (MemAvailable in /proc/meminfo, available on kernels 3.14, emulated on kernels 2.6.27+, otherwise the same as free)
Excerpt from the /proc documentation.
MemAvailable: An estimate of how much memory is available for starting new applications, without swapping. Calculated from MemFree, SReclaimable, the size of the file LRU lists, and the low watermarks in each zone. The estimate takes into account that the system needs some page cache to function well, and that not all reclaimable slab will be reclaimable, due to items being in use. The impact of those factors will vary from system to system.
The function used to estimate available memory can be found in mm/page_alloc.c
source file located in the kernel source tree.
long si_mem_available(void) { long available; unsigned long pagecache; unsigned long wmark_low = 0; unsigned long pages[NR_LRU_LISTS]; struct zone *zone; int lru; for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++) pages[lru] = global_node_page_state(NR_LRU_BASE + lru); for_each_zone(zone) wmark_low += zone->watermark[WMARK_LOW]; /* * Estimate the amount of memory available for userspace allocations, * without causing swapping. */ available = global_zone_page_state(NR_FREE_PAGES) - totalreserve_pages; /* * Not all the page cache can be freed, otherwise the system will * start swapping. Assume at least half of the page cache, or the * low watermark worth of cache, needs to stay. */ pagecache = pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE]; pagecache -= min(pagecache / 2, wmark_low); available += pagecache; /* * Part of the reclaimable slab consists of items that are in use, * and cannot be freed. Cap this estimate at the low watermark. */ available += global_node_page_state(NR_SLAB_RECLAIMABLE) - min(global_node_page_state(NR_SLAB_RECLAIMABLE) / 2, wmark_low); if (available < 0) available = 0; return available; } EXPORT_SYMBOL_GPL(si_mem_available);
Parse command output regardless of version
Use awk
to parse free
output and use different data depending on the content of the header line.
$ free -m | \ awk '{ if (NR==1) { if (/cached$/) {vesion=0} else {version=1} } else if (/^Mem/) { if (version==0) {print "Free/Available: " $4 + $6 + $7 "/" $2 " MiB"} else {print "Free/Available: " $7 "/" $2 " MiB"} } }'
Output for the old free
utility.
Free/Available: 4956/15975 MiB
Output for the new free
utility.
Free/Available: 4335/15975 MiB
Parse proc filesystem
Inspect /proc/meminfo
file.
$ cat /proc/meminfo
MemTotal: 16358744 kB MemFree: 2914240 kB MemAvailable: 4439720 kB Buffers: 189188 kB Cached: 1973396 kB SwapCached: 86076 kB Active: 2374260 kB Inactive: 853088 kB Active(anon): 894680 kB Inactive(anon): 668992 kB Active(file): 1479580 kB Inactive(file): 184096 kB Unevictable: 0 kB Mlocked: 0 kB SwapTotal: 15998972 kB SwapFree: 15746616 kB Dirty: 0 kB Writeback: 0 kB AnonPages: 993164 kB Mapped: 400748 kB Shmem: 498912 kB Slab: 3957608 kB SReclaimable: 199856 kB SUnreclaim: 3757752 kB KernelStack: 21968 kB PageTables: 33952 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 24178344 kB Committed_AS: 3655512 kB VmallocTotal: 34359738367 kB VmallocUsed: 0 kB VmallocChunk: 0 kB HardwareCorrupted: 0 kB AnonHugePages: 751616 kB CmaTotal: 0 kB CmaFree: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 7296640 kB DirectMap2M: 9406464 kB
Parse this file to read and display available/total memory.
$ awk '{ if (/MemAvailable:/) {mem_available=$2}; if (/MemTotal:/) {mem_total=$2}; if (mem_available && mem_total) {print "Available/Total memory: " int(mem_available/1024) "/" int(mem_total/1024) " MiB";exit} }' /proc/meminfo
Available/Total memory: 4335/15975 MiB