Post

Sessizce Ölen Süreçler: Sinyaller, SIGKILL ve OOM Gerçeği

Process'iniz aniden yok mu oldu? Loglarda sadece 'Killed' mi yazıyor? Linux sinyal mekanizmasını, 'kill -9'un tehlikelerini ve Kernel'ın seri katili OOM Killer'ın kimi neden seçtiğini, bir dedektif titizliğiyle inceliyoruz.

Sessizce Ölen Süreçler: Sinyaller, SIGKILL ve OOM Gerçeği

Bir sistem yöneticisinin, bir DevOps mühendisinin veya bir Backend geliştiricisinin, sabah kahvesini içerken karşılaşabileceği en kısa, en net ve en korkunç korku hikayesi tek bir kelimeden oluşur:

“Killed.”

Terminalde çalıştırdığınız kritik script, gece boyunca çalışması gereken veri işleme programı, yüzlerce müşteriye hizmet veren API servisi veya devasa bir veritabanı aniden yok olmuştur. Ortada bir ceset yoktur. Geriye ne bir “Segmentation Fault” (Core Dump), ne bir yazılım dili “Exception Trace”i, ne de masanın üzerine bırakılmış bir veda mektubu kalmıştır. Konsolda veya log dosyasının en sonunda sadece o soğuk, o ifadesiz kelime yazar: Killed.

Peki, katil kim? Kıskanç ve sinirli bir sistem yöneticisi mi? (Manuel kill komutu) Hafızasını kaybeden ve paniğe kapılan bir Kernel mı? (OOM Killer) Yoksa programın kendisi, varoluşsal sancılar çekip intihar mı etti? (Abort/Segfault)

Bu yazıda, Linux’un Cinayet Masası’na (Forensics) geçici görevle katılıyoruz. Süreçlerin (Process) nasıl sonlandırıldığını, Linux’un ölüm dili olan Sinyaller (Signals) dünyasını, kill -9 kullanmanın neden bir “savaş suçu” sayılabileceğini ve Linux Kernel’ın içindeki soğukkanlı tetikçi OOM Killer‘ın (Out Of Memory Killer) kurbanlarını neye göre, nasıl seçtiğini öğreneceğiz.

Olay yeri şeridini çekin. Cesedi incelemeye başlıyoruz.

📡 1. Ölümün Dili: Linux Sinyalleri (Signals)

Linux’ta bir sürecin (process) bitmesi için, eğer kodu bitip kendisi çıkmadıysa (exit()), dışarıdan bir dış müdahale gerekir. Bu müdahalenin teknik adı Sinyaldir. Sinyaller, Kernel’ın (veya yetkili diğer süreçlerin) bir uygulamaya gönderdiği kısa, net, asenkron ve acil durum SMS’leridir. Bu SMS’lerin içeriği metin değil, birer sayıdan ibarettir (1, 9, 15 gibi).

Terminalde kill -l yazarsanız, bu ölümcül listenin tamamını (64 adet) görürsünüz. Ama bir “Cinayet Dedektifi” olarak bizi ilgilendiren 3 büyük “Ölüm Emri” vardır:

A. SIGTERM (Signal 15) - “Lütfen Evi Boşalt”

  • Anlamı: “Termination Signal”. Nezaketle, usulüne uygun sonlandırma.
  • Analoji: Ev sahibinin kapıyı çalıp, yüzünde bir tebessümle “Hocam kontrat bitti, ay sonuna kadar evi toparlayıp, çöplerini atıp, anahtarı teslim edip çıkarsan sevinirim” demesidir.
  • Davranış: Program bu sinyali yakalayabilir (Catch edebilir).
    • Veritabanı bağlantılarını (Close Connection) kapatır.
    • Hafızada (RAM) tuttuğu ve henüz diske yazmadığı verileri (Flush Buffer) diske yazar. Veri kaybını önler.
    • Geçici dosyaları (/tmp) temizler.
    • Log dosyasına “Kapanıyorum, her şey için teşekkürler” yazar ve exit(0) ile çıkar (Graceful Shutdown).
  • Varsayılan Komut: Konsolda kill <PID> yazdığınızda, varsayılan olarak bu (15) sinyal gönderilir.

B. SIGINT (Signal 2) - “Yeter Artık”

  • Anlamı: “Interrupt”. Klavyeden donanım kesmesi.
  • Analoji: Biri hararetli bir şekilde konuşurken, elinizi havaya kaldırıp “Bir saniye, yeter, kes!” demeniz gibidir.
  • Davranış: Terminalde çalışan bir programa Ctrl+C yaptığınızda Kernel bu sinyali gönderir. Program kodunda bu sinyal (“Handler”) tanımlıysa, “İşlemi iptal ediyorum” diyerek temiz bir çıkış yapabilir. Tanımlı değilse, pat diye kapanır.

C. SIGKILL (Signal 9) - “Kafasına Sık”

  • Anlamı: “Kill Signal”. Kesin, Ani ve Tartışmasız Ölüm.
  • Analoji: Ev sahibinin kapıyı çalmadan, anahtarı istemeden, dozerle gelip evi, içindeki eşyalarla ve kiracıyla birlikte yıkmasıdır. Veya SWAT timinin camdan girmesidir.
  • Davranış: Bu sinyal yakalanamaz, engellenemez, bloke edilemez, göz ardı edilemez.
    • Programın “Dur bir log yazayım”, “Dosyayı kapatayım”, “Veritabanına commit edeyim” deme şansı SIFIRDIR.
    • Kernel, o milisaniyede programın CPU ile, RAM ile, Disk ile olan tüm ilişkisini bıçak gibi keser.
    • Masada açık kalan dosyalar bozulabilir (Corrupted Files).
    • Yarım kalan veriler sonsuza dek kaybolur.
    • Log dosyasında “Program durdu” bile yazmaz. Log aniden kesilir.

⚠️ Neden kill -9 Alışkanlık Yapmamalı? Acemi sistem yöneticileri, kapanmayan (veya yavaş kapanan) bir program görünce sabırsızlanıp refleks olarak kill -9 <PID> yapıştırır. Bu çok tehlikeli bir alışkanlıktır.

  • Veri Bütünlüğü: Eğer bir MySQL/PostgreSQL veritabanına kill -9 atarsanız, veritabanı dosyaları tutarsız hale gelebilir (“Index Corruption”) ve saatlerce “Recovery” yapmak zorunda kalabilirsiniz.
  • Yetimler: Eğer birçok alt süreç (“Child Process”) üreten bir ana sürece (Parent, örneğin Apache veya Chrome) kill -9 atarsanız, ana süreç anında öldüğü için çocuklarına “Siz de ölün” diyemez. Geride sistem kaynaklarını tüketen başıboş “Yetim Süreçler” (Orphan Zombies) bırakırsınız.

Altın Kural: Her zaman önce kill -15 (SIGTERM) gönderin. 10 saniye bekleyin. Program inatla kapanmıyorsa (Hung State), işte o zaman son çare olarak kill -9 kullanın.

🩸 2. OOM Killer: Kernel’ın İçindeki Seri Katil

Gelelim o meşhur, o gizemli Killed mesajının (eğer siz öldürmediyseniz) en büyük baş şüphelisine. Uygulamanız gayet güzel çalışıyordu. Kimse sisteme girip kill komutu yazmadı. Ama sabah geldiniz, süreç yok.

Sistem loglarını (dmesg -T veya /var/log/kern.log) açtınız ve şu korkunç, kırmızı satırları gördünüz:

1
2
[Tue Jan 12 04:00:01 2026] Out of memory: Killed process 15203 (java) total-vm:5120000kB, anon-rss:2048000kB, file-rss:0kB, shmem-rss:0kB
[Tue Jan 12 04:00:01 2026] oom_reaper: reaped process 15203 (java), now anon-rss:0kB

Tebrikler. OOM Killer (Out Of Memory Killer) tarafından ziyaret edildiniz. Kernel’ın özel timi, sunucunuzu kurtarmak için uygulamanızı infaz etti.

Neden Olur? (Overcommit Yalanı)

Linux Kernel’ı, RAM yönetimi konusunda biraz “yalancıdır” (veya teknik tabirle “optimisttir”). Sisteminizde fiziksel olarak 8GB RAM var diyelim.

  1. Uygulama A: “Bana 4 GB yer ayır (malloc)” der. Kernel: “Tamam, al.” (Aslında vermez, sadece söz verir / Virtual Memory).
  2. Uygulama B: “Bana 6 GB yer ayır” der. Kernel: “Sana da tamam, dert etme.”

Toplamda 10GB söz verdi. Ama fizikselde 8GB var. Buna Memory Overcommit denir. Mantığı şudur: “Nasılsa herkes aynı anda, ayırttığı tüm alanın her baytını kullanmaz. Uçak şirketlerinin her uçuşta ‘Fazla Bilet’ (Overbooking) satması gibi.”

Ama gün gelir, Uygulama A ve B aynı anda o alanları gerçekten doldurmaya başlarsa (“Physical Write”), RAM biter. Swap alanı da biter. Kernel köşeye sıkışır. Ne yapacak? Kernel Panic (Mavi Ekranın Linux hali) geçirip tüm sunucuyu, işletim sistemini dondurmak mı? Yoksa “Sistemin (Geminin) yaşaması için birinin (Yükün) denize atılması gerekiyor” kararı mı? Kernel yaşamak ister. Ve OOM Killer’ı devreye sokar.

Kurban Nasıl Seçilir? (oom_score)

OOM Killer, eline silahı alıp rastgele ateş etmez. Bir mantığı, bir algoritması, soğukkanlı bir puanlama sistemi (badness score) vardır. Her süreç (PID) için bir karne hazırlar:

  1. RAM Kullanımı: En çok RAM tüketen, en büyük hedeftir. (Zenginler ilk ölür).
  2. Ömür: Kısa süredir çalışan süreçler, uzun süredir çalışan emektar süreçlere göre daha kolay harcanır.
  3. Kullanıcı: root ve sistem süreçleri (sshd, systemd) korunmaya çalışılır, normal kullanıcı süreçleri harcanır.

Bu puanı canlı olarak görebilirsiniz. cat /proc/<PID>/oom_score komutu size 0 ile 1000 arasında bir puan verir. Puan ne kadar yüksekse, namlu o sürece o kadar yakındır.

🕵️‍♂️ 3. Vaka Analizi: Kayıp Java Uygulaması ve Container Dünyası

Bir e-ticaret şirketinde, Production ortamındaki Java (Spring Boot) uygulamasının her 3 günde bir, düzensiz aralıklarla çöktüğü (“Killed” olduğu) raporlanıyor. Yazılımcılar hemen Heap Dump inceliyor: “Memory Leak yok, Heap boyutunu 2GB ile sınırladık (-Xmx2G). Uygulama taş çatlasa 2GB harcıyor.” Sysadmin htop‘a bakıyor: “Sunucuda (Host) 16GB RAM var, boş yer çok. RAM bitmiyor ki!”

Ama dmesg yalan söylemez. OOM Killer, Java’yı vurmuştur. Peki neden?

Analiz: Yazılımcı Heap’i 2GB sınırlamış olabilir. Ama modern bir Java uygulamasının bir de “Off-Heap” belleği vardır:

  • Metaspace: Class metadata’ları.
  • Thread Stacks: Her thread için (varsayılan 1MB) alan.
  • GC Overhead: Garbage Collector’ın çalışırken kullandığı alan.
  • Direct Buffers: (NIO) Hızlı I/O için kullanılan alanlar.

Bunlarla beraber Java süreci aslında 2.5GB veya 3GB RAM tüketebilir. Daha da önemlisi, bu uygulama bir Docker Container içinde mi çalışıyor?

Eğer Kubernetes YAML dosyasında limit: 2Gi verildiyse; Sizin uygulamanız (Heap + Off-Heap) 2.01 GiB olduğu anda, Host makinede 1 Terrabyte RAM olsa bile Cgroups (Container Runtime) devreye girer. “Sen sana ayrılan 2GB limitini aştın” der ve OOM Killer’ı sadece o container içine gönderir. Loglarda “Killed” görürsünüz. Host makinenin RAM’i boştur ama Container ölmüştür.

Çözüm:

  1. Doğru Limit: Java’nın -Xmx değeri, Container limitinin (Memory Limit) asla %100’ü olmamalı. %70-75’i olmalı (Örn: Container 4GB ise Heap 3GB). Geriye kalan %25, işletim sistemi ve Off-Heap için bırakılmalı.
  2. Skor Ayarı (Geçici Hack): Kritik bir süreciniz varsa (örneğin SSHD), Kernel’a “Buna dokunma” diyebilirsiniz. echo -1000 > /proc/<PID>/oom_score_adj. Bu komut Kernel’a “Bu sürece -1000 puan ver” der. Böylece puanı 0’ın altına düşer ve OOM Killer onu atlar (“Dokunulmazlık”). (Java uygulamaları için bu tavsiye edilmez, çünkü RAM gerçekten biterse Kernel Panic yaşanır. Ama SSHd gibi yönetim servisleri için hayat kurtarır).

4. “Segmentation Fault” (İntihar) vs “Killed” (Cinayet)

Bazen loglarda “Killed” yazmaz. Şunu görürsünüz: Segmentation fault (core dumped)

Bu bir cinayet değildir. Bu bir intihardır. OOM Killer veya bir başkası karışmamıştır. Program (Process), hafızada (RAM) kendisine ait olmayan, erişim izni olmayan bir adrese yazmaya veya okumaya çalışmıştır.

  • NULL pointer’a erişim (Olmayan bir nesneyi çağırmak).
  • Buffer Overflow (Dizinin sınırını taşmak).
  • RAM’in donanımsal olarak bozuk bir sektörüne denk gelme.

Bu durumda Kernel, “Hop, orası senin tarlan değil!” diyerek sürece SIGSEGV (Signal Segmentation Violation) sinyalini çakar. Process anında ölür ve geriye (ayarlıysa) bir “Core Dump” dosyası (hafızanın fotoğrafı) bırakır. Suçlu: %99 ihtimalle Yazılımcı (C/C++ kodu hatası, Pointer hatası). %1 ihtimalle bozuk RAM (Donanım).

🚑 5. Cinayeti Kim İşledi? (Auditd ile Takip)

Senaryo: OOM Killer masum (dmesg temiz). Segfault yok (Exit code 139 değil). Ama süreç “Killed” oldu (Exit code 137). Demek ki, etten kemikten bir İNSAN (veya bir script), manuel olarak kill komutunu çalıştırdı. Ya sıkılan bir Junior Sysadmin, ya hatalı yazılmış bir Crontab scripti, ya da bir CI/CD Deploy aracı süreci öldürdü.

“Ben yapmadım” diyen kullanıcıyı nasıl bulursunuz? history komutuna bakmak yetmez (silebilir). Çözüm: Auditd (Linux Audit System). Linux varsayılan olarak “kim kimi öldürdü” logunu tutmaz (çok log oluşur diye). Ama açabilirsiniz.

1
2
3
4
# audit kuralı ekle: "kill" sistem çağrısını (syscall) izle
# arch=b64: 64-bit sistem
# -k process_killer: Bu logu "process_killer" etiketiyle ara
sudo auditctl -a always,exit -F arch=b64 -S kill -k process_killer

Bu kuraldan sonra, birisi (veya bir script) kill komutunu kullandığında /var/log/audit/audit.log dosyasına şu düşer:

1
type=SYSCALL ... syscall=62 (kill) ... a0=1234 (hedef pid) a1=9 (sinyal=SIGKILL) ... auid=1000 (yapan user=ahmet) exe="/usr/bin/bash"

Çeviri: “Ahmet kullanıcısı (auid=1000), Bash terminalinden, 1234 PID’li sürece 9 numaralı sinyali (SIGKILL) gönderdi.”

Artık faili meçhul cinayet yoktur. Kanıt vardır.

🛠️ Debugging Kontrol Listesi

Process’iniz sessizce öldüğünde panik yapmayın, şu sırayı takip edin:

  1. Dmesg Kontrolü (Hızlı Triage): dmesg -T | grep -E "kill|oom|out of memory" Kırmızı yazılar, OOM Killer izi, RAM miktarları var mı?

  2. Exit Code Analizi: Process’i systemd veya docker çalıştırıyorsa, “Exit Code” (Çıkış Kodu) en büyük ipucudur.
    • Exit Code 137 -> (128 + 9). Yani SIGKILL. Genelde OOM Killer veya manuel kill -9.
    • Exit Code 143 -> (128 + 15). Yani SIGTERM. Birisi kibarca “Dur” demiş (Deploy, Restart).
    • Exit Code 139 -> (128 + 11). Yani SIGSEGV. Segfault (Yazılım hatası, İntihar).
  3. Kernel Overcommit Ayarı: Sunucunuz kritikse ve çok sık OOM oluyorsa, Kernel’ın “Hayal satmasını” engelleyebilirsiniz. sysctl vm.overcommit_memory=2. Bu modda Kernel, elinde garanti RAM yoksa malloc isteyen programa “HAYIR” döner. Program “Killed” olmaz, “Memory Allocation Error” verip kendisi hata işleyebilir. (Riskli bir ayardır, dikkat).

  4. Auditd: Hala bulamadıysanız, auditd ile kill syscall’ını dinlemeye alın. Katil mutlaka bir iz bırakacaktır.

👋 Son Söz: Katil Her Zaman Uşak Değildir

Linux dünyasında süreçlerin ölümü, yaşam döngüsünün (Lifecycle) doğal bir parçasıdır. Ancak “Sessiz ve ani ölümler”, sistem yönetiminin en büyük baş ağrısıdır. Gördük ki “Killed” yazısı bir son değil, bir başlangıçtır. Altında bellek yetersizliği (OOM), yanlış Container limitleri, hatalı C kodları (Segfault) veya kötü niyetli bir kill -9 komutu yatabilir.

Kernel, OOM Killer ile aslında kötülük yapmaz; batmakta olan gemiyi kurtarmak için en ağır yükü denize atan soğukkanlı bir kaptan gibi davranır. Size düşen görev, gemiye (Sunucuya) kapasitesinden fazla yük (Process/Memory) yüklememek ve kaptanın kimi atacağını (oom_score_adj) iyi yönetmektir.

Bu serinin sonuna yaklaşıyoruz. Dosya sistemi dedektifliği yaptık, kayıp ağ paketlerini aradık, donan zamanı inceledik ve şimdi de ceset incelemesi yaptık. Linux artık sizin için kara bir kutu değil, şeffaf, kuralları olan ve her şeyi loglayan bir makineye dönüşmeye başladı.

Bir sonraki (ve muhtemelen final) yazımızda, her şeyi birleştireceğiz: “Linux Sistem Hardening ve Performans Tuning: Fabrika Ayarlarından Production Canavarına.” Varsayılan (Default) ayarların neden yetersiz olduğunu ve bir Linux sunucusunu nasıl “kurşun geçirmez” hale getireceğimizi konuşacağız.

O zamana kadar, RAM’iniz bol, swap‘iniz boş, süreçleriniz (Process) ölümsüz olsun.

This post is licensed under CC BY 4.0 by the author.