Bellek Sızıntısı Tespiti: smem Aracının Kullanımı

Bir sunucu yavaşlamaya başladığında, disk dolmadığında, CPU da çıkmaz değilken ve ağ da sorunsuzken, gözler hemen RAM’e kayar. Peki ya RAM doluymuş gibi görünüyor ama neden dolduğunu tam olarak tespit edemiyorsanız? İşte bu noktada klasik top veya free komutları yetersiz kalmaya başlıyor. Paylaşımlı bellek, yazarken kopyala (copy-on-write) mekanizmaları ve çok sayıda çalışan process düşünüldüğünde, “bu process ne kadar RAM yiyor?” sorusunun cevabı sandığınızdan çok daha karmaşık. smem tam bu karmaşıklığı çözmek için var.

smem Nedir ve Neden Farklıdır?

smem, Linux sistemlerinde bellek kullanımını gerçekçi biçimde raporlayan bir araçtır. Klasik araçlardan farkını anlamak için önce Linux’un belleği nasıl hesapladığını bilmek gerekiyor.

Bir process başladığında, işletim sistemi o process için bellek ayırır. Ama modern sistemlerde işler bu kadar basit değil. Birçok process aynı kütüphaneleri (örneğin libc) paylaşır. Bu paylaşımlı bellek bölgelerine shared memory denir. top veya ps gibi araçlar genellikle VSZ (Virtual Size, sanal bellek) ve RSS (Resident Set Size, fiziksel RAM’de bulunan kısım) değerlerini gösterir.

Sorun şu: RSS, paylaşımlı belleği her process için tam olarak sayar. Yani 10 process aynı 10 MB’lık kütüphaneyi paylaşıyorsa, RSS toplamı 100 MB gösterir. Ama gerçekte bu 10 MB sadece bir kez bellekte bulunuyor.

smem ise üç farklı metrik sunar:

  • USS (Unique Set Size): Sadece o processe ait, hiçbir başka processle paylaşılmayan bellek miktarı. Process öldüğünde gerçekten serbest kalacak bellek budur.
  • PSS (Proportional Set Size): Paylaşımlı belleği, onu kullanan process sayısına bölerek hesaplar. 10 process 10 MB paylaşıyorsa, her birine 1 MB yazar. Sistem genelinde en gerçekçi toplamı bu verir.
  • RSS (Resident Set Size): Klasik RSS değeri, karşılaştırma için gösterilir.

Bellek sızıntısı tespitinde en değerli metrik USS‘dir. Bir process’in USS değeri sürekli artıyorsa, o process belleği tahsis edip serbest bırakmıyor demektir.

Kurulum

smem çoğu dağıtımda paket deposunda mevcuttur:

# Debian/Ubuntu
sudo apt install smem

# RHEL/CentOS/Rocky Linux
sudo dnf install smem

# Arch Linux
sudo pacman -S smem

# Fedora
sudo dnf install smem

Python tabanlı bir araç olduğundan Python 3 de sistemde kurulu olmalıdır. Kurulum sonrası çalışıp çalışmadığını doğrulamak için:

smem --version

Temel Kullanım

smem‘i parametresiz çalıştırdığınızda, o anki kullanıcının processlerini listeler:

smem

Çıktı şu şekilde görünür:

  PID User     Command                         Swap      USS      PSS      RSS
 1842 ahmet    bash                               0      668      782     2100
 2341 ahmet    vim /etc/nginx/nginx.conf          0     4512     5021    11200
 2890 ahmet    python3 monitor.py                 0    12400    13100    18900

Tüm kullanıcıların processlerini görmek için root yetkisiyle veya sudo ile çalıştırın:

sudo smem

Sıralama Seçenekleri

Bellek sızıntısı tespitinde en çok kullandığım parametre USS’e göre azalan sıralamadır:

sudo smem -s uss -r
  • -s: Sıralama kriteri (uss, pss, rss, swap, pid, user, command)
  • -r: Reverse, yani azalan sıra (büyükten küçüğe)

PSS’e göre sıralamak için:

sudo smem -s pss -r

Önemli Parametreler

  • -k: Değerleri kilobyte yerine insan okuyabilir formatta gösterir (KB, MB, GB)
  • -s [alan]: Belirtilen alana göre sırala
  • -r: Sıralamayı tersine çevir
  • -u: Kullanıcı bazında özet göster
  • -m: Bellek haritası (mapping) bazında göster
  • -w: Sistem geneli özeti göster
  • -P [regex]: Process adına göre filtrele
  • -U [kullanici]: Belirli kullanıcının processlerini filtrele
  • -n: Başlık satırını gizle
  • -t: Toplam satırı ekle
  • -p: Yüzde olarak göster
  • –pie: Pasta grafik oluştur (grafik ortamda)
  • –bar: Bar grafik oluştur

Gerçek Dünya Senaryosu 1: Web Sunucusu Bellek Sızıntısı

Diyelim ki bir production PHP-FPM sunucunuz var ve her gece 03:00’te yeniden başlatılıyor çünkü aksi takdirde sistem belleği tükenip web sitesi çöküyor. Klasik bir bellek sızıntısı vakası.

Önce PHP-FPM processlerinin anlık durumuna bakalım:

sudo smem -k -s uss -r -P php-fpm

Bu komut tüm php-fpm processlerini USS’e göre sıralar ve insan okuyabilir format kullanır. Çıktıda şuna benzer bir şey göreceksiniz:

  PID User     Command                         Swap      USS      PSS      RSS
12341 www-data php-fpm: worker process          0    145.2M   148.1M   162.3M
12289 www-data php-fpm: worker process          0    134.8M   137.6M   151.2M
12201 www-data php-fpm: worker process          0    98.4M    101.2M   115.8M
12156 www-data php-fpm: worker process          0    45.2M    48.1M    62.3M
12089 www-data php-fpm: master process          0    12.1M    13.4M    18.2M

Worker processlerin birbirinden bu kadar farklı USS değerleri göstermesi alarm verici. En eski process (düşük PID) en fazla belleği tutuyor. Bu, zaman içinde biriken sızıntının klasik göstergesi.

Şimdi bu durumu belirli aralıklarla izleyelim. Basit bir bash scripti:

#!/bin/bash
# php_memory_watch.sh
LOG_FILE="/var/log/php_memory_leak.log"
INTERVAL=300  # 5 dakikada bir

echo "Timestamp,PID,USS_KB,PSS_KB,RSS_KB" > $LOG_FILE

while true; do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    sudo smem -n -s uss -r -P "php-fpm: worker" | while read pid user cmd swap uss pss rss; do
        echo "$TIMESTAMP,$pid,$uss,$pss,$rss" >> $LOG_FILE
    done
    echo "--- $TIMESTAMP ---" >> $LOG_FILE
    sleep $INTERVAL
done

Bu scripti çalıştırıp birkaç saat sonra loglara baktığınızda, hangi PID’lerin USS değerinin sürekli arttığını net olarak görebilirsiniz.

Gerçek Dünya Senaryosu 2: Sistem Geneli Bellek Dağılımı

Sunucunuzda ne çalıştığını ve belleğin nereye gittiğini net görmek için önce sistem özetine bakın:

sudo smem -w -k

Çıktı şuna benzer:

Area                           Used      Cache   Noncache
firmware/hardware                 0          0          0
kernel image                      0          0          0
kernel dynamic memory         1.2G      912.4M     311.6M
userspace memory              6.8G      234.1M       6.6G
free memory                   1.1G      1.1G          0

Ardından kullanıcı bazında özet:

sudo smem -u -k -s uss -r
User         Count     Swap      USS      PSS      RSS
www-data        48        0    2.1G     2.3G     2.8G
postgres         8        0    1.2G     1.2G     1.4G
redis            1        0   234.1M   235.2M   241.3M
root            23        0   145.2M   198.4M   412.3M
ahmet            6        0    45.2M    58.9M   124.1M

Bu çıktıdan görüyoruz ki www-data kullanıcısı (yani web sunucusu) toplam 2.1 GB USS tutuyor. Bu normalin üzerinde mi? Geçmiş değerlerle karşılaştırmanız gerekiyor. Bunun için düzenli cron job çalıştırmak iyi bir alışkanlık:

# /etc/cron.d/smem_monitor
*/15 * * * * root smem -u -k -s uss -r -n >> /var/log/smem_summary.log 2>&1

Gerçek Dünya Senaryosu 3: Belirli Bir Processi Derinlemesine İncelemek

Şüpheli bir process bulduğunuzda, onun hangi bellek bölgelerini kullandığını görmek için -m parametresini kullanın:

sudo smem -m -P "python3 app.py" -k

Bu komut, o process’in açtığı her bellek mapping’ini listeler. Hangi .so dosyaları, hangi anonim bellek bölgeleri var, hepsini görürsünüz.

Belirli bir PID için daha detaylı bilgi almak isterseniz, Linux’un kendi /proc filesystem’ini de kullanabilirsiniz. smem ile PID’yi tespit ettikten sonra:

# Processi bul
sudo smem -k -s uss -r | head -20

# Detaylı bellek haritası
sudo cat /proc/12341/smaps | grep -E "^(Size|Rss|Pss|Shared|Private)" | 
awk '{sum[$1] += $2} END {for (key in sum) printf "%s: %d kBn", key, sum[key]}'

Bu çıktı size o processın kaynakları nasıl kullandığını çok detaylı gösterir.

Periyodik İzleme ile Sızıntı Tespiti

Bellek sızıntısını tek anlık ölçümle yakalamak zordur. Önemli olan zaman içindeki değişimi izlemek. Bunun için aşağıdaki scripti kullanabilirsiniz:

#!/bin/bash
# leak_detector.sh - Bellek sızıntısı dedektörü
# Kullanim: ./leak_detector.sh <process_adi> <esik_mb> <sure_dakika>

PROCESS_NAME="${1:-nginx}"
THRESHOLD_MB="${2:-100}"
DURATION_MIN="${3:-60}"
INTERVAL=60
ITERATIONS=$((DURATION_MIN * 60 / INTERVAL))
LOG="/tmp/leak_detect_${PROCESS_NAME}.log"

echo "Izleme basliyor: $PROCESS_NAME | Esik: ${THRESHOLD_MB}MB | Sure: ${DURATION_MIN} dakika"
echo "Timestamp | PID | USS_MB | Degisim_MB" | tee $LOG

declare -A INITIAL_USS

# Baslangic degerlerini kaydet
while IFS= read -r line; do
    pid=$(echo $line | awk '{print $1}')
    uss_kb=$(echo $line | awk '{print $5}')
    INITIAL_USS[$pid]=$uss_kb
done < <(sudo smem -n -P "$PROCESS_NAME" 2>/dev/null)

for i in $(seq 1 $ITERATIONS); do
    sleep $INTERVAL
    TIMESTAMP=$(date '+%H:%M:%S')

    while IFS= read -r line; do
        pid=$(echo $line | awk '{print $1}')
        uss_kb=$(echo $line | awk '{print $5}')
        uss_mb=$((uss_kb / 1024))

        initial=${INITIAL_USS[$pid]:-$uss_kb}
        diff_kb=$((uss_kb - initial))
        diff_mb=$((diff_kb / 1024))

        echo "$TIMESTAMP | PID:$pid | USS:${uss_mb}MB | +${diff_mb}MB" | tee -a $LOG

        if [ $diff_mb -gt $THRESHOLD_MB ]; then
            echo "UYARI: PID $pid $THRESHOLD_MB MB esigini asti! Toplam artis: ${diff_mb}MB"
            # Buraya mail veya Slack bildirimi eklenebilir
        fi
    done < <(sudo smem -n -P "$PROCESS_NAME" 2>/dev/null)

    echo "---"
done

echo "Izleme tamamlandi. Log: $LOG"

Bu scripti şöyle çalıştırırsınız:

chmod +x leak_detector.sh
./leak_detector.sh "java" 200 120

Bu örnek java processlerini 120 dakika boyunca izler ve USS’i 200 MB’dan fazla artan processler için uyarı verir.

smem ile Swap Kullanımını Birlikte Değerlendirmek

Bellek sızıntısı zamanla swap kullanımına da yansır. smem swap bilgisini de gösterir:

sudo smem -k -s swap -r | head -20

En fazla swap kullanan processleri listeler. Swap’a düşen processlerin USS değerleri yüksekse, bu sistem hafızasının tükenmeye başladığının işaretidir. Bu durumda hem sızıntıyı bulup gidermek, hem de kısa vadeli çözüm olarak belirli processleri yeniden başlatmak gerekebilir.

Swap ve USS’yi birlikte değerlendiren bir özet almak için:

sudo smem -k -s pss -r -t | tail -5

-t parametresi en alta toplam satırı ekler. Bu toplamı düzenli aralıklarla loglamak, sisteminizin bellek trendini takip etmenizi sağlar.

Grafik Çıktı Almak

smem grafik çıktı da üretebilir. Sunucu başında X11 forwarding ile çalışıyorsanız veya yerel bir Linux masaüstü kullanıyorsanız:

# Pasta grafik - process bazında PSS
sudo smem --pie name -s pss

# Bar grafik - kullanici bazinda
sudo smem -u --bar name -s uss

Grafik çıktıyı PNG dosyasına kaydetmek için --png parametresini ekleyin:

sudo smem --pie name -s pss --png /tmp/memory_pie.png

Bu PNG’yi monitoring sistemine veya raporlara eklemek son derece kullanışlı. Özellikle management’a “neden daha fazla RAM lazım” diye anlatırken bir pasta grafik, satır satır sayılardan çok daha etkili olur.

Monitoring Sistemleriyle Entegrasyon

Zabbix veya Prometheus gibi sistemlerle entegre etmek için smem çıktısını parse etmeniz gerekiyor. İşte basit bir Prometheus textfile collector scripti:

#!/bin/bash
# smem_prometheus.sh
# /var/lib/node_exporter/textfile_collector/smem.prom dosyasini gunceller

OUTFILE="/var/lib/node_exporter/textfile_collector/smem.prom"
TMPFILE=$(mktemp)

echo "# HELP process_uss_bytes Unique Set Size in bytes" > $TMPFILE
echo "# TYPE process_uss_bytes gauge" >> $TMPFILE

sudo smem -n -s uss -r 2>/dev/null | while read pid user cmd swap uss pss rss; do
    # Komut adini temizle
    clean_cmd=$(echo "$cmd" | tr ' /:' '___' | cut -c1-50)
    uss_bytes=$((uss * 1024))
    pss_bytes=$((pss * 1024))

    echo "process_uss_bytes{pid="$pid",user="$user",cmd="$clean_cmd"} $uss_bytes" >> $TMPFILE
    echo "process_pss_bytes{pid="$pid",user="$user",cmd="$clean_cmd"} $pss_bytes" >> $TMPFILE
done

mv $TMPFILE $OUTFILE
chmod 644 $OUTFILE

Bunu 5 dakikada bir çalıştıran bir cron job ekleyin:

*/5 * * * * root /usr/local/bin/smem_prometheus.sh

Artık Grafana’da bu metrikleri görselleştirebilir, eşik değerlerinde alert alabilirsiniz.

smem’in Sınırları

Her araç gibi smem‘in de sınırları var:

  • Yavaş çalışır: /proc filesystem’i taradığından, çok sayıda process olan sistemlerde birkaç saniye sürebilir. Production sistemlerde sık aralıklarla çalıştırırken bu gecikmeyi göz önünde bulundurun.
  • Root yetkisi gerektirir: Diğer kullanıcıların processlerini görmek için root veya sudo şart.
  • Kernel thread’leri göstermez: Sadece userspace processleri raporlar.
  • Anlık görüntü: Sürekli izleme için kendiniz sarmalayıcı script yazmanız gerekir (ya da watch komutunu kullanın).

watch ile gerçek zamanlı izleme:

watch -n 5 'sudo smem -k -s uss -r | head -20'

Bu komut her 5 saniyede ekranı güncelleyerek en fazla USS kullanan 20 processi gösterir. Kısa süreli gözlem için idealdir.

Karşılaştırmalı Analiz: smem vs Diğer Araçlar

top veya htop kullandığınızda gördüğünüz RES (yani RSS) değeri, paylaşımlı belleği çok sayar. Bunu anlamak için küçük bir deney yapabilirsiniz:

# top ciktisindaki toplam RSS
ps aux | awk '{sum += $6} END {print sum/1024 " MB"}' 

# smem'in PSS toplami (daha gercekci)
sudo smem -t -n | tail -1 | awk '{print $6/1024 " MB PSS"}'

Çoğu sistemde RSS toplamı, sistemdeki toplam fiziksel RAM’den daha yüksek çıkar. Oysa PSS toplamı gerçek kullanıma çok daha yakındır. Bu fark, smem‘in ne kadar değerli olduğunu gösterir.

Özet: smem Kullanım Kılavuzu Hızlı Başvuru

Sık kullandığım komutları bir araya getiriyorum:

  • sudo smem -k -s uss -r: En fazla unique bellek kullanan processleri listele
  • sudo smem -u -k -s uss -r: Kullanıcı bazında bellek özeti
  • sudo smem -w -k: Sistem geneli bellek dağılımı
  • sudo smem -k -P nginx: Sadece nginx processlerini göster
  • sudo smem -t -k: Toplam satırıyla birlikte listele
  • sudo smem -m -P "myapp": Process bellek mapping detayları
  • watch -n 5 'sudo smem -k -s uss -r | head -15': Gerçek zamanlı izleme

Sonuç

Bellek sızıntısı, sistem yöneticilerinin en sinir bozucu problemlerinden biridir. Yavaş yavaş gerçekleşir, bazen sadece haftalar sonra kendini gösterir ve hangi processın suçlu olduğunu bulmak klasik araçlarla gerçekten zordur. smem, özellikle USS metriği sayesinde bu işi ciddi ölçüde kolaylaştırır. Paylaşımlı belleği doğru hesaplaması, sizi yanlış suçlamaların önüne geçer.

Eğer sunucunuzda henüz smem kullanmıyorsanız, bugün kurun ve sistem geneli bir USS anlık görüntüsü alın. Bu değerleri bir yere kaydedin. Bir hafta, bir ay sonra tekrar ölçün. Trendin nereye gittiğini gördüğünüzde, sorun büyümeden müdahale etme şansınız olur. Production’da reaktif değil, proaktif olmak, iyi bir sysadmin’in en temel özelliğidir.

Yorum yapın