Linux free Command: A Deep Dive into Memory Monitoring and OOM Troubleshooting
Linux free Command: A Deep Dive into Memory Monitoring and OOM Troubleshooting#
Server OOM again? I spent hours staring at top trying to figure out where the memory went. Turns out, free is the right tool for memory analysis. Here’s what I learned about its internals and practical usage.
Understanding the Four Lines of Output#
$ free -h
total used free shared buff/cache available
Mem: 15Gi 8.5Gi 1.2Gi 256Mi 5.3Gi 5.8Gi
Swap: 2.0Gi 512Mi 1.5Gi
Many people get confused: why doesn’t used + free equal total? And what’s available?
The key is buff/cache. Linux uses idle memory for buffer cache and page cache to speed up file I/O. So:
- free: Completely unused memory
- buff/cache: Memory used for caching (reclaimable)
- available: Memory programs can actually allocate (free + reclaimable cache)
To judge if memory is tight, look at available, not free.
/proc/meminfo: Where free Gets Its Data#
free reads from /proc/meminfo:
$ head -20 /proc/meminfo
MemTotal: 16384000 kB
MemFree: 1228800 kB
MemAvailable: 6029312 kB
Buffers: 524288 kB
Cached: 5242880 kB
SwapCached: 0 kB
Active: 4194304 kB
Inactive: 3145728 kB
The core logic of free is parsing these fields:
// Simplified free command logic
void print_meminfo() {
FILE *fp = fopen("/proc/meminfo", "r");
unsigned long mem_total, mem_free, buffers, cached;
// Parse line by line
while (fgets(line, sizeof(line), fp)) {
if (sscanf(line, "MemTotal: %lu kB", &mem_total));
else if (sscanf(line, "MemFree: %lu kB", &mem_free));
else if (sscanf(line, "Buffers: %lu kB", &buffers));
else if (sscanf(line, "Cached: %lu kB", &cached));
}
// Calculate
unsigned long used = mem_total - mem_free - buffers - cached;
unsigned long buff_cache = buffers + cached;
printf("Mem: %lu %lu %lu %lu %lu\n",
mem_total, used, mem_free, buff_cache, ...);
}
The available calculation is more complex, involving the MemAvailable field (kernel 3.14+) or estimating reclaimable memory.
Common Parameters#
-h: Human-Readable Format#
$ free -h
Mem: 15Gi 8.5Gi 1.2Gi 256Mi 5.3Gi 5.8Gi
Automatically converts units (K/M/G/T), smarter than -m (MB) or -g (GB).
-b/-k/-m/-g: Specify Units#
$ free -m # Display in MB
$ free -g # Display in GB
$ free -b # Display in bytes
Use -b for monitoring scripts to calculate percentages.
-s N: Continuous Monitoring#
$ free -s 1 # Refresh every second
$ free -s 5 -c 10 # Refresh every 5 seconds, 10 times total
Use -c to limit iterations and avoid infinite loops.
-t: Show Total#
$ free -t
total used free shared buff/cache available
Mem: 16384000 8847360 1257472 262144 6279168 6029312
Swap: 2097152 524288 1572864
Total: 18481152 9371648 2830336
Adds a Total row combining Mem and Swap.
-w: Wide Output, Separate Buffer and Cache#
$ free -w
total used free shared buffers cache available
Mem: 16384000 8847360 1257472 262144 524288 5754880 6029312
Buffers is block device cache, cache is filesystem cache. Separating them gives more clarity.
Practical Scenarios#
1. Detecting Memory Pressure#
$ free -h
Mem: 15Gi 14Gi 512Mi 256Mi 512Mi 400Mi
available is only 400Mi - memory is tight but not yet OOM. Time to scale or optimize.
2. Swap Usage Analysis#
$ free -h
Swap: 2.0Gi 1.8Gi 200Mi
Swap at 90% means severe memory shortage. The system is thrashing, performance will tank.
3. Observing Cache Effects#
# First read of large file
$ time cat 10GB.log > /dev/null
real 0m45.123s
# Second read (cache hit)
$ time cat 10GB.log > /dev/null
real 0m2.456s
# Observe cache growth
$ free -h
buff/cache increased from 5.3Gi to 10.2Gi
Linux automatically uses idle memory for caching to accelerate file access.
4. Manually Dropping Cache#
# Drop page cache
$ echo 1 > /proc/sys/vm/drop_caches
# Drop dentries and inodes
$ echo 2 > /proc/sys/vm/drop_caches
# Drop all cache
$ echo 3 > /proc/sys/vm/drop_caches
Warning: Avoid in production; it hurts performance. Sync first:
$ sync && echo 3 > /proc/sys/vm/drop_caches
5. Monitoring Script Example#
#!/bin/bash
# Memory monitoring script
THRESHOLD=90 # Memory usage threshold
while true; do
MEM_INFO=$(free | grep Mem)
TOTAL=$(echo $MEM_INFO | awk '{print $2}')
USED=$(echo $MEM_INFO | awk '{print $3}')
PERCENT=$(echo "scale=2; $USED * 100 / $TOTAL" | bc)
if (( $(echo "$PERCENT > $THRESHOLD" | bc -l) )); then
echo "$(date): Memory usage ${PERCENT}% exceeds threshold!"
# Send alert
fi
sleep 60
done
Common Misconceptions#
1. Low free means memory shortage#
Actually, Linux’s design philosophy is “idle memory is wasted”. Low free means cache is being utilized.
2. High used means memory pressure#
Wrong. used includes buff/cache, which can be released immediately.
The right metric: Look at available, not free or used.
3. Any swap usage is a problem#
Not necessarily. Minor swap usage is normal, like programs dormant on disk. The key is whether swap is growing.
free vs Other Tools#
| Tool | Advantage | Use Case |
|---|---|---|
| free | Quick overview | Daily checks |
| top/htop | Real-time process sorting | Find memory hogs |
| vmstat | Detailed memory stats | Performance analysis |
| /proc/meminfo | Complete memory info | Deep diagnostics |
| smem | Process actual memory (PSS) | Accurate accounting |
smem uses PSS (Proportional Set Size), more accurate than top’s RES:
$ smem -t -k -s rss
PID User Command Swap USS PSS RSS
12345 nginx nginx 0 45M 52M 68M
Summary#
free is simple, but reading it requires understanding Linux memory management:
- Check available to judge memory pressure
- buff/cache is good - don’t panic at low free
- Continuously growing swap is the danger signal
- Use
/proc/meminfofor deep diagnostics
Next time you face OOM, start with free -h for the big picture, then use smem or htop to find specific processes.
Related: Linux df Disk Space Monitoring | Linux du Directory Size Statistics