CPU yang penuh hanya membuat proses mengantri; memori yang habis membuat kernel membunuh proses. Itulah sebabnya pemantauan memori punya urgensi berbeda: kehabisan RAM berujung pada OOM killer yang menghentikan layanan tanpa permisi, dan sering kali korban yang dipilih justru proses paling penting seperti database. Kabar baiknya, Linux tidak membiarkan RAM menganggur — sisa memori dipakai sebagai cache disk — sehingga membaca laporan memori butuh kebiasaan yang benar agar tidak panik terhadap angka yang kelihatannya buruk. Pada chapter ini kita bedah /proc/meminfo, membaca free dengan tepat, menemukan proses paling boros, lalu membangun laporan memori otomatis dengan awk.

/proc/meminfo: Sumber dari Semua Alat #

Semua alat pemantauan memori — free, top, htop — sebenarnya hanya memformat ulang satu file: /proc/meminfo. Kernel menulis statistik memori ke file ini dalam format Field: nilai kB yang sangat stabil, sehingga skrip kita bisa mengandalkannya. Field yang paling sering dibaca:

FieldArti
MemTotaltotal RAM fisik yang dikenal kernel
MemFreeRAM yang benar-benar tidak dipakai apa pun
MemAvailableperkiraan RAM yang bisa dipakai proses baru tanpa menukar swap
Bufferscache metadata filesystem (superblock, direktori)
Cachedcache isi file yang pernah dibaca dari disk
SwapTotal, SwapFreeukuran swap dan sisanya (dibedah di Chapter Swap Space )

Dua field pertama sering disalahartikan: MemFree rendah bukan berarti sistem bahaya. Isi Buffers dan Cached adalah salinan data disk yang sengaja ditahan di RAM supaya pembacaan berikutnya cepat — begitu aplikasi butuh memori, kernel melepas cache itu dalam hitungan detik. Karena itulah kernel sejak 2014 menyediakan MemAvailable: perkiraan memori yang benar-benar bisa dipakai, dihitung dari MemFree ditambah cache yang bisa direclaim. Pedoman praktisnya sederhana — pantau MemAvailable, bukan MemFree. Spesifikasi seluruh field ada di proc(5) .

free -h dibedah #

Perintah free meringkas /proc/meminfo menjadi dua baris. Opsi -h membulatkan satuan agar mudah dibaca manusia, dan berikut contoh tampilan free -h pada mesin dengan RAM 16 GiB:

text
               total        used        free      shared  buff/cache   available
Mem:              15.5Gi       2.2Gi       7.8Gi       150Mi       5.5Gi       11.6Gi
Swap:             2.0Gi          0B       2.0Gi

Baris Mem punya enam kolom: total, used (dipakai proses), free (sungguhan kosong), shared (memori bersama seperti tmpfs), buff/cache (jumlah Buffers + Cached), dan available (padanan MemAvailable). Baris Swap melaporkan pemakaian ruang tukar di disk. Perhatikan ironi pada baris Mem: kolom free hanya 7.8 GiB dari 15.5 GiB, padahal kolom available menunjukkan 11.6 GiB — selisihnya adalah cache yang siap dilepas kapan saja.

Opsi lain yang berguna: free -m menampilkan angka dalam MiB (enak untuk skrip karena satuannya tetap), dan free -h -s 5 menyegarkan tampilan tiap 5 detik untuk mengamati tren singkat. Opsi lengkapnya ada di free(1) .

Proses Paling Boros Memori #

Ketika available menipis, pertanyaan berikutnya adalah “siapa pelakunya?”. Perintah ps menjawabnya dengan mengurutkan berdasarkan kolom %MEM:

bash
ps aux --sort=-%mem | head -6

Berikut contoh tampilan hasilnya pada server aplikasi yang sedang memproses laporan besar:

text
USER   PID %CPU %MEM      VSZ    RSS TTY  STAT START  TIME COMMAND
mysql  1121  1.2 18.4 4312100 2950000 ?   Sl  Mei01 120:15 /usr/sbin/mysqld
budi   2482 25.8  6.9  864312  1105210 ?  Sl  14:02   3:11 chromium --type=renderer
budi   1902  4.1  3.2  512080   512340 ?  Sl  13:58   0:41 code-server
www-data 990  0.8  1.9  210430  310200 ?  S   09:00   1:03 /usr/sbin/nginx

Kolom %MEM adalah perbandingan RSS — resident set size, bagian memori proses yang benar-benar ditempati di RAM — terhadap total memori. Kolom VSZ jauh lebih besar karena menghitung seluruh ruang alamat yang dialokasikan, termasuk yang belum pernah disentuh; angka itu hampir tidak berguna untuk memperkirakan tekanan memori nyata. Urutan di atas menunjukkan mysqld menempati 18.4% RAM — kandidat pertama untuk diperiksa konfigurasinya (misalnya batas innodb_buffer_pool_size).

OOM Killer: Ketika Memori Benar-benar Habis #

Bila MemAvailable dan swap sama-sama habis, kernel masuk ke mode darurat: OOM (out of memory) killer menilai semua proses dengan skor “kejahatan” — ukuran memori, lama berjalan, prioritas — lalu membunuh skor tertinggi supaya sistem tetap hidup. Korban tidak bisa diprediksi dari luar: bisa jadi proses render video Budi, bisa jadi database utama. Jejaknya selalu tertinggal di log dengan pesan Out of memory: Killed process, dan kapan membaca jejak itu — beserta prosedur lengkap menangani kehabisan memori — kita bahas di Chapter Troubleshooting Performance .

Latihan: Persentase Terpakai dari meminfo #

Sama seperti chapter sebelumnya, angka /proc/meminfo berbeda di setiap mesin dan berubah tiap detik, jadi latihan parsing kita kerjakan pada fixture statis yang formatnya sama persis dengan file asli. Nilai-nilainya sengaja konsisten dengan tampilan free -h di atas: MemTotal 16308124 kB adalah 15.5 GiB dan MemAvailable 12181000 kB adalah 11.6 GiB. Metrik yang dihitung: terpakai = MemTotal − MemAvailable, karena MemAvailable sudah memperhitungkan cache yang bisa direclaim:

bash
cat > meminfo.txt <<'AKHIR'
MemTotal:       16308124 kB
MemFree:         8154032 kB
MemAvailable:   12181000 kB
Buffers:          213408 kB
Cached:          4012032 kB
SwapCached:            0 kB
SwapTotal:       2097148 kB
SwapFree:        2097148 kB
AKHIR

awk '
/^MemTotal:/     { total = $2 }
/^MemAvailable:/ { avail  = $2 }
END {
  terpakai = total - avail
  printf "RAM: %.1f GiB total | %.1f GiB terpakai | %.1f%%\n", \
         total/1048576, terpakai/1048576, terpakai/total*100
}' meminfo.txt

Output yang Dihasilkan:

text
RAM: 15.6 GiB total | 3.9 GiB terpakai | 25.3%

Bedah potongan awk di atas:

  1. Baris 13–14 (/^MemTotal:/ ...): dua pola sederhana menangkap field yang dibutuhkan. Nilai berada di $2 karena format file selalu NamaField: nilai kB — pola pemisahan field default awk (spasi berurutan) langsung memisahkannya.
  2. Baris 15–19 (blok END): perhitungan baru dijalankan setelah seluruh file terbaca. terpakai = total - avail sengaja memakai MemAvailable, bukan MemFree, agar cache yang bisa direclaim tidak dihitung sebagai beban. Pembagian 1048576 mengubah kB menjadi GiB, dan 100 membalik rasio menjadi persen.
  3. Baris 17–18 (tanda \): backslash di akhir baris melanjutkan perintah printf ke baris berikutnya — murni untuk keterbacaan, hasilnya sama dengan satu baris panjang.

Hasilnya membaca jujur: mesin ini baru memakai 25% kapasitas RAM-nya untuk proses, sisanya adalah ruang lega.

Skrip Laporan Memori #

Untuk pemantauan rutin, potongan di atas kita kemas menjadi skrip yang juga menilai swap dan memberi status. Dua fixture menguji dua keadaan: mesin sehat dan mesin yang sudah meminjam swap:

bash
cat > meminfo.txt <<'AKHIR'
MemTotal:       16308124 kB
MemFree:         8154032 kB
MemAvailable:   12181000 kB
Buffers:          213408 kB
Cached:          4012032 kB
SwapCached:            0 kB
SwapTotal:       2097148 kB
SwapFree:        2097148 kB
AKHIR

printf '%s\n' \
  'MemTotal:        8123456 kB' \
  'MemFree:          412000 kB' \
  'MemAvailable:     730000 kB' \
  'SwapTotal:       2097148 kB' \
  'SwapFree:        1048574 kB' > meminfo-padat.txt

cat > laporan-memori.sh <<'SKRIP'
#!/bin/bash
# laporan-memori.sh <file-meminfo>
awk '
/^MemTotal:/     { total = $2 }
/^MemAvailable:/ { avail = $2 }
/^SwapTotal:/    { swap_total = $2 }
/^SwapFree:/     { swap_free  = $2 }
END {
  terpakai = total - avail
  pct = terpakai / total * 100
  printf "RAM  : %6.1f GiB total | %6.1f GiB terpakai | %.1f%%\n", \
         total/1048576, terpakai/1048576, pct
  if (pct >= 90)
    print "RAM  : status KRITIS"
  else if (pct >= 75)
    print "RAM  : status WASPADA"
  else
    print "RAM  : status SEHAT"
  swap_pakai = swap_total - swap_free
  printf "Swap : %6.1f GiB total | %6.1f GiB terpakai\n", \
         swap_total/1048576, swap_pakai/1048576
}' "$1"
SKRIP

bash laporan-memori.sh meminfo.txt
bash laporan-memori.sh meminfo-padat.txt

Output yang Dihasilkan:

text
RAM  :   15.6 GiB total |    3.9 GiB terpakai | 25.3%
RAM  : status SEHAT
Swap :    2.0 GiB total |    0.0 GiB terpakai
RAM  :    7.7 GiB total |    7.1 GiB terpakai | 91.0%
RAM  : status KRITIS
Swap :    2.0 GiB total |    1.0 GiB terpakai

Bedah skrip di atas:

  1. Baris 12–17 (printf '%s\n' ...): fixture kedua dibuat dengan satu perintah printf yang menerima banyak argumen — format %s\n diulang untuk tiap argumen sehingga tiap baris tercetak sendiri; alternatif ringkas untuk heredoc saat barisnya pendek-pendek.
  2. Baris 19–42 (laporan-memori.sh): pola /^Field:/ tetap sama, hanya bertambah SwapTotal dan SwapFree. Blok END kini mencetak laporan dua baris lalu menilai status lewat tangga if — ambang 75% sebagai waspada dan 90% sebagai kritis.
  3. Baris 44–45: dua fixture diuji. Mesin pertama sehat (25.3%). Mesin kedua memakai 91.0% RAM — status KRITIS — dan sudah meminjam 1.0 GiB swap; kombinasi yang lazim sebelum OOM killer ikut turun tangan.

Di mesin nyata, skrip ini bekerja langsung pada file asli: bash laporan-memori.sh /proc/meminfo. Teknik awk multi-baris yang dipakai di sini sudah kita latih di Chapter awk . Setelah CPU dan memori, tinggal satu sumber daya yang paling sering membuat layanan berhenti mendadak: ruang disk yang habis — topik Chapter Disk Monitoring .