06 - İşlemlerle çalışmak

Ebeveyn-Çocuk ilişkisi

Linux’da sistemin çalıştırdığı görevler, yani işlemler ağaç yapısındadır. Çalışan tüm uygulamalar birer işleme sahiptir. Bunlara komut verdiğiniz terminal veya üzerinde çalıştığınız grafiksel ortam da (web tarayıcı, dosya yönetici vb.) dahildir. Örneğin üzerinde komut verdiğiniz terminalin işlem ağacı şu şekilde olabilir:

    init
    `- xterm
       `- bash

pstree komutu ile sisteminizin tüm işlem ağacını görüntüleyebilirsiniz:


    $ pstree
    init-+-acpid
         |-4*[agetty]
         |-agiletrack---java---19*[{java}]
         |-apache2---8*[apache2]
         |-bonobo-activati---{bonobo-activati}
         |-5*[dbus-daemon]
         |-dhcpcd
         |-gconfd-2
         |-gnome-keyring-d
         |-gnome-power-man
         |-gnome-screensav
         |-gnome-settings----{gnome-settings-}
         |-4*[gnome-vfs-daemo]
         |-gnome-volume-ma
         |-gpg-agent
         |-hald---hald-runner-+-hald-addon-acpi
         |                    |-hald-addon-cpuf
         |                    `-hald-addon-stor
         |-java---15*[{java}]
         |-login---bash---startx---xinit-+-X
         |                               `-gnome-session-+-gnome-panel
         |                                               |-metacity
         |                                               |-nautilus
         |                                               `-{gnome-session}
    [...]

Bazı işlemlerin direkt olarak init’e bağlı olduğunu göreceksiniz. Bu işlemler özel gereksinimlerinden dolayı bu şekilde çalışmaktadır. Her işlemin kendine özel bir numarası (PID) bulunur. İlk, yani 1 numaralı işlem init, sistemin açılışında çekirdek tarafından çalıştırılır ve sistem için gerekli servisleri başlatmakla sorumludur. Her işlem birden fazla işlemi başlatabilir, yani birden çok çocuk işleme (child) sahip olabilir. Bir işlem sonlandığında (öldüğünde): Ona bağlı, yani onun çocuğu durumundaki tüm işlemler de init tarafından sonlandırılır. Eğer bir işlem, yukarıdaki örnek komutta da gördüğünüz gibi, kendisini başlatan işlem yerine init‘in çocuğu durumunda çalışıyorsa, bunun amacı genellikle kendisini başlatan işlem sonlandığında kendisinin sonlanmaması gerektiğindendir. Yukardaki ağaçta buna dhcpcd işlemini örnek gösterebiliriz. Bu servis DHCP protokolü üzerinden ağdaki IP adresinizi belirlemeye yardımcı olur ve çalışır durumda değilse IP adresinizi bir süre sonra kaybedersiniz.

İşlem Sahipliği

Bir işlem başladığında, genelde onu başlatan işlemin kullanıcı ve grup bilgisini aynen alıp devam eder. Bunu şöyle örneklendirelim: Bir kullanıcı sisteme girdiğinde, login işlemi kullanıcının adı ve grubunu kullanarak bir oturum başlatır ve artık kullanıcının çalıştırdığı tüm işlemler (bu oturum üzerinden çalıştırılacağı için) bu kullanıcının ve grubunun ID’sini alacaktır. Yani kullanıcının yetkileri, çalıştırdığı işlemlere de uygulandığından, bu işlemlerle kendi yetkisi haricinde işlem yapamaz. Bazı işlemler çekirdekten özel olarak farklı bir grup ya da kullanıcı ile çalışmayı talep edecektir. Bu da işlemin kendisine setuid veya setgid iznini atamayla elde edilebilir. Bu izin: İşlemin, çalıştırılan kullanıcının yetkileriyle değil, dosyanın sahibi olan kullanıcı/grubun yetkileriyle çalışmasını sağlayacaktır. Örnek olarak kullanıcının parolasını değiştirmeye yarayan passwd komutunu gösterebiliriz:

    $ ls -lh /bin/passwd
    -rws--x--x 1 root root 46K Jun 29 11:01 /bin/passwd

Gördüğünüz gibi, dosyanın sahibi root kullanıcısı. İzinlerde setuid izni de var (-rws--x--x içerisindeki s). Bir kullanıcı passwd komutunu çalıştırdığında, komut root kullanıcısının yetkileri ile çalışacaktır. Bu tür bir ayarlama passwd komutu için gerekli; çünkü çalıştığında sadece root kullanıcısının yazma izni olan bazı sistem dosyalarında değişiklik yapması gerekecek (/etc/passwd ve /etc/shadow). /etc/shadow dosyası normal kullanıcılar için okumaya dahi kapalı.

İşlem Bilgisi İnceleme

Linux’da işlemlerin bilgilerine erişmek için bazı yardımcı araçlar var, birkaçını inceleyelim…

İşlem Listeleme

İşlemleri listelemek için kullanacağımız programların başında ps geliyor. Bir terminalde çalıştırdığımızda, bize mevcut oturumdaki işlemlerin bir listesini verir:

$ ps
  PID TTY          TIME CMD
24064 pts/3    00:00:00 bash
24116 pts/3    00:00:00 ps

Gösterilen sütunlar:

  1. PID - İşlemin ID’si
  2. TTY - Kontrol eden terminal (UNIX’den kalma bir deyim. Direkt terminal üzerinde çalışmadığımız için sanal terminal ismi olan pts’i görüyoruz)
  3. TIME - İşlemin aldığı çalışma zamanı. Bu örnekte iki işlem de pek CPU işi gerektirmediğinden saniyeden az çıktısı alıyoruz.
  4. CMD - Komutun kendisi

ps, genelde parametreleri ile kullanılır. Örneğin ps -e ile aynı veriyi tüm sistemdeki uygulamalar ile alırsınız. ps -f ile üst işlemin ID’si ve işlemin başlama saati gibi bazı ek bilgiler de gelir. Ayrıca sonuçlarda filtreleme de yapabilirsiniz. Örn. kullanıcı adına göre (ps -u kullanıcıadı), komuta göre (ps -C komut) veya aktif olarak işlemci harcayanlar (ps -r) gibi. Daha fazla bilgi için ps komutunun man sayfalarını inceleyebilirsiniz. İşlem listesini incelemek için kullanılan bir diğer araç da top programı. Size güncel işlem listesini, dilediğiniz kritere göre sıralayarak gösteren ve (siz başka süre seçmezseniz) 5 saniyede bir yenilenen bir arayüze sahip. İlk çalıştırdığınızda CPU kullanımına göre listeleme yapmakta:

top - 10:19:47 up 6 days,  6:41,  5 users,  load average: 1.00, 1.27, 0.92
 Tasks: 120 total,   1 running, 119 sleeping,   0 stopped,   0 zombie
 Cpu(s):  3.2%us,  0.7%sy,  0.0%ni, 95.6%id,  0.3%wa,  0.1%hi,  0.0%si,  0.0%st
 Mem:   1545408k total,  1490968k used,    54440k free,   177060k buffers
 Swap:  2008084k total,      132k used,  2007952k free,   776060k cached

   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  4458 haldaemo  16   0  5488 3772 2388 S  2.0  0.2   4:23.69 hald
 27255 swift     15   0  2272 1064  768 R  2.0  0.1   0:00.01 top
     1 root      15   0  1612  544  468 S  0.0  0.0   0:00.48 init
     2 root      12  -5     0    0    0 S  0.0  0.0   0:00.00 kthreadd
     3 root      39  19     0    0    0 S  0.0  0.0   0:00.45 ksoftirqd/0
     4 root      10  -5     0    0    0 S  0.0  0.0   0:01.95 events/0
     5 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 khelper
    60 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 kblockd/0
    61 root      11  -5     0    0    0 S  0.0  0.0   0:25.77 kacpid
    62 root      11  -5     0    0    0 S  0.0  0.0   0:09.60 kacpi_notify
   171 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 ata/0
   172 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 ata_aux
   173 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 ksuspend_usbd
   176 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 khubd
   178 root      10  -5     0    0    0 S  0.0  0.0   0:00.01 kseriod
   196 root      10  -5     0    0    0 S  0.0  0.0   0:01.13 kswapd0
   197 root      20  -5     0    0    0 S  0.0  0.0   0:00.00 aio/0

Oldukça fazla bilgi var. Sırayla bakalım.

    top - 10:19:47 up 6 days,  6:41,  5 users,  load average: 1.00, 1.27, 0.92

İlk satır sistemin çalışma zamanını (bu örnekte sistem 6 gün 6 saat 41 dakikadır çalışıyor), sisteme giriş yapmış kullanıcı sayısı (farklı kullanıcılar değil, toplamda var olan oturum sayısı) ve sistem yükünü gösteriyor. Sistem yükü, çoğu insanın yanlış anladığı bir kavram. Bu değer, verilen aralıkta işlemci zamanını kullanan veya isteyen işlem sayısını veriyor. Örneğin yukardaki örnekte:

  • Son 1 dakika içinde işlemciyi kullanmak isteyen ortalama olarak 1 işlem var
  • Son 5 dakika içinde işlemciyi kullanmak isteyen ortalama işlem sayısı 1.27
  • Son 15 dakika içinde işlemciyi kullanmak isteyen ortalama işlem sayısı 0.92
    Tek işlemcili/çekirdekli sistemlerde, uzun süreler için (örn. 15 dakikalık değerde) sayının 1’den fazla olması istenen bir durum değil. Çekirdek sayısı arttıkça bu değer de artabilir.

      Tasks: 120 total,   1 running, 119 sleeping,   0 stopped,   0 zombie
    

Bu satırda da sistemde çalışan işlemlerin toplam sayısı (120); aktif olarak çalışmayanlar (119), çalışanlar (1, top komutunun kendisi), durdurulanlar (0) ve zombiler (0) olarak listeleniyor. Durdurulan işlem demek, sonradan tekrar uyandırılmak üzere bekletilen, ancak şu anda herhangi bir girdi kabul etmeyen ve iş yapmayan işlem demek. Zombi ise, aslında sonlanmış ancak üst işleminin (ebeveyninin) bu durumdan haberi olmayan işlem demek. Çekirdek bu işlemin durum bilgisini, ebeveyni durumunu sorguladığında vermek için halen tutuyor.

    Cpu(s):  3.2%us,  0.7%sy,  0.0%ni, 95.6%id,  0.3%wa,  0.1%hi,  0.0%si,  0.0%st

Bu satırda da işlemcinin yük bilgisi var: Kullanıcı işlemleri (us), sistem/çekirdek kullanımı (sy), nice eklenmiş işlemler (ni), işlemci boşta (id), okuma/yazma işini bekleyenler (wa), donanımsal kesilmeler (hi), yazılımsal kesilmeler (si) ve sanal işlemci çalma (st). Çoğunun ismi yeterince açık. Anlaşılmayacak olanlardan “sanal işlemci çalma”, sanal bir işlemcinin gerçek işlemciyi beklemesidir ve sanallaştırma kullanmayan normal bir kullanıcı/ortam için önemsizdir. nice konusuna da aşağıda değineceğiz.

    Mem:   1545408k total,  1490968k used,    54440k free,   177060k buffers
    Swap:  2008084k total,      132k used,  2007952k free,   776060k cached

Burada da hafıza kullanımı var. Toplam 1.5 Gbyte hafıza kullanılabilir. 1.45Gbyte kullanımda ve 54Mbyte boş durumda. Kullanılan hafızanın 117 Mbyte’ı çekirdek tarafından kullanılıyor. Ayrıca yine kullanılan hafızanın 776 Mbyte’ı önbellek (cache) olarak kullanımda, yani hafıza gereken durumlarda temizlenebilir, (yani cache kullanımından korkmamalısınız). Swap alanı çok az kullanılıyor. 2Gbyte alandan sadece 132 Kbyte kullanımda.

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
     4458 haldaemo  16   0  5488 3772 2388 S  2.0  0.2   4:23.69 hald
    ...

Geri kalan çıktı da işlem listesi, gösterilen sütunlar:

  1. İşlemin ID’si.
  2. İşlemin sahibi olan kullanıcı (USER).
  3. İşlemin önem değeri (PR). Yüksek değer, daha fazla önem demek. Önem değerleri çekirdek tarafından belirlenmekte.
  4. İşlemin nice değeri (NI). Eğer kullanıcı bir “nice” değeri atamış ise, işlem buna göre öncelik kazanacaktır. Değer -20 ile +19 arasındadır. -20 en önemli demektir. Yani genel olarak listedeki nice değeri ne kadar aşağıdaysa önem değeri o kadar yüksek görülebilir.
  5. İşleme atanan sanal hafıza (VIRT). Bu değere işleme herhangi bir kaynak üzerinde atanan tüm hafıza dahildir.
  6. İşlemin gerçekten elinde tuttuğu hafıza (RES).
  7. İşlemin tuttuğu hafızadan paylaşılabilir olma ihtimali olan değer (SHR). “İhtimal” diyoruz, çünkü paylaşılabilir alan henüz paylaşılmamış olabileceğinden kesin değer bilinemiyor.
  8. İşlemin durumu (S). Birkaç durum görebilirsiniz: Uykuda (S - sleeping), çalışıyor (R - running), uyandırılamayan uykuda (D), izleniyor veya durdurulmuş (T) ve de zombi (Z).
  9. CPU kullanımı (%CPU)
  10. Hafıza kullanımı (%MEM - RES’i temel alır)
  11. Çalışma zamanı (TIME+)
  12. Komut (COMMAND)



İşlem Detayı

Tek işlem hakkında detaylı bilgi almanız da mümkün, örneğin işlemin kullanmakta olduğu dosyalar veya bağlantılar. Bu tür bilgilere lsofkomutu ile ulaşabilirsiniz. İncelemek istediğiniz işlemin ID’sini (PID) vermeniz yeter (lsof -p PID). Ancak lsof çok daha yetenekli. Örneğin sistemdeki bir portu hangi işlemin kullandığını görmek için kullanabilirsiniz:

    # lsof -i :443
    COMMAND   PID   USER   FD   TYPE DEVICE SIZE NODE NAME
    apache2  4346   root    3u  IPv4  11484       TCP *:https (LISTEN)

Aynı işi yapabilecek diğer bir araç da fuser:

    # fuser -v 443/tcp
                         USER        PID ACCESS COMMAND
    443/tcp:             root       4346 F.... apache2

Aynı işlemi dosyalar için de yapabilirsiniz. Örneğin bir dosyayı hangi işlemin kullandığını görmek isterseniz: fuser -v /dosyanin/yolu

Arka Plan İşlemleri

Bazı işlemler arkaplanda çalışabilir. Bunun sebebi işlemin özel olarak arka planda çalışmasının istenmesi ( karışıklık olmaması adına buna “job” diyelim) veya işlemin servis (daemon) olarak çalışması olabilir. Servisler (daemon’lar), çalıştırıldığı oturuma bağlı kalmayan süreçlerdir. Genellikle bir servisi çalıştırdığınız zaman, işlem sonlanmış gibi, terminale geri dönersiniz. Ancak işlem sonlanmamıştır ve çalışmasını arkaplanda sürdürmektedir. Bir işlemin servis olarak çalışıp çalışmaması, işlemin kendi yapısı ile ilgilidir. Çoğu çalışan servis, mevcut oturumda çalışacak şekilde geri getirilemez, tüm işlerini arkaplanda yapar. “Job”lar ise mevcut oturumda çalışan işlemlerdir ancak ekranınızda görünüp klavyenizden girdi almazlar. Sonuç olarak işlem arka planda devam ederken, kullanıcı terminalde farklı işlemler gerçekleştirebilir. Bir işlemi arka plana göndermek için komutun sonuna “&” işareti koyabilirsiniz. Örneğin eix-update komutunu arka planda çalıştıralım:

    # eix-update &

Mevcut oturumunuzdaki arka plan işlerini görüntülemek için jobs komutunu kullanabilirsiniz:

    # jobs
    [1]- Running           eix-update &

İşlemi tekrar ön plana almak için fg komutunu kullanabilirsiniz. Komutu parametre olmadan kullanırsanız arka plana gönderdiğiniz son işlem geri gelecektir. Farklı bir işlemi çağırmak için sıra numarasını kullanmanız gerek. Örneğin 3. işi ön plana getirmek için:

    # fg %3

Eğer çalışan bir işlemi arka plana göndermek isterseniz Ctrl-Z kullanabilirsiniz. Ctrl-Z çalışan işleme ara verir. İşlemin arkaplanda devam etmesi için bg kullanmalısınız:

    # eix-update
    (... işlem başlar)
    (Ctrl-Z'ye basıyoruz)
    [1]+ Stopped         eix-update
    # bg
    [1]+ eix-update &

İşlemleri arkaplana gönderirken kullanırken unutmamanız gereken bazı noktalar:

  • İşlem (servis değilse) mevcut oturumla ilişkilenmekte. Yani oturumu kapattığınızda, arka planda bulunan veya görünürde olan tüm işler de onunla birlikte sonlanacaktır.
  • İşlemler arka plana alınsa bile, çıktıları halen ekranınıza gelecektir. Bunu istemiyorsanız, çıktıyı > ile yönlendirebilirsiniz. Örneğin işlemin basacağı normal (1) ve hata (2) çıktılarını bir dosyaya kaydetmek için:

              # eix-update > eix-mesajlari.log 2>&1 &
    

Diğer bir popüler kullanım şekli de, önemsiz ise çıktıyı tamamen yok saymaktır:

        # eix-update > /dev/null 2>&1 &

İşlem Davranışları

Programlar genelde kullanıcı bir uygulama seçtiğinde veya bir komut çalıştırdığında yüklenir. Bunların yanı sıra farklı bir program tarafından çalıştırılabilir veya çekirdek tarafından da başlatılabilirler (ama muhtemelen çekirdek tarafından başlatılan tek işlem init’dir). Biraz da işlemlerin çalışırken sergilediği davranışları ve yapabileceğimiz değişiklikleri inceleyelim.

Komut Geri Dönüşleri

Program çalıştırmanın en basit yolu, komut satırından komut vermeniz. Çalışarak işlemini tamamlayan bir program kapanıp, arkasında bir “dönüş kodu” (“_exit code_” veya “_return code_“) bırakır. Bu koda bakarak işlemin sonucu hakkında bilgi alabilirsiniz. Dönüş kodu 0 ile 225 arasında bir sayı olarak dönecektir. Bazı programlar 255’den daha büyük (hatta negatif) dönüş kodları ile sonlanabilir. Teknik bir sınırlama olmasa da, çoğu uygulama 0-255 aralığı dışında dönüş kodunu desteklemediği için, bu tavsiye edilmemektedir. Çalışmasını başarılı şekilde sonlandıran tüm işler dönüş kodunu 0 (sıfır) olarak verir (veya vermelidir). Sıfırdan farklı bir kod dönen uygulamalar, işlerini tam olarak başarılı şekilde bitirememiş demektir. ksh veya bash gibi, POSIX uyumlu bir shell kullanıyorsanız (POSIX standartları gereği) son işlemin dönüş kodunu $? ile alabilirsiniz:

    $ ls -l
    ...
    $ echo $?
    0
    $ ls -z
    ls: invalid option -- z
    Try `ls --help' for more information
    $ echo $?
    2

Bu kodlar işlemin düzgün sonlanıp sonlanmadığını anlamanız ve hata durumunda farklı işler yapabilmenizi sağlayan mantıklı scriptler yazabilmeniz için önemlidir.

Önem ve “nice” Değeri

Linux’da bir işlemin önemini kendiniz atayamazsınız. Bu işi sizin yerinize çekirdek yapar. Bunu yaparken işlemin girdi/çıktı durumu, önceki işlemci tüketimleri ve işlem yaparken kilitlediği kaynaklar gibi farklı değerleri göz önünde bulundurur. Yine de, çekirdeğe bir işlemin öneminin ne kadar olması gerektiği ile ilgili fikrinizi belirtebilirsiniz (ve çekirdek sizi önemseyecektir). Sizin atayabileceğiniz bu değere “_nice_” değeri denir ve -20 ile 19 arasında değişebilir. Çekirdeğe, uygulamanın diğer işlemlere karşı ne kadar toleranslı olabileceğinin sayısal karşılığıdır. Eksi değerler (-20 ile -1 arası) çekirdeğe, uygulamanın o kadar da toleranslı olmadığını belirtmekte, çekirdek de bu tür uygulamalara genellikle daha fazla işlemci zamanı alabilmesi için yüksek öncelik vermektedir.

Sadece root kullanıcısı nice değerini değiştirebilir.

Bu sistem sayesinde müdahale etmenize gerek kalmadan, arkaplanda çok sayıda farklı öneme sahip işlemi uzun süreler çalıştırabilirsiniz. nice aracı ile dilediğiniz bir uygulamayı dilediğiniz değerde başlatabilirsiniz. Örneğin Gentoo sistem güncellemesini en düşük önemde (en yüksek nice değeri ile), yani arkaplanda vakit buldukça çalışır gibi çalıştırmak için:

    # nice -n 19 emerge -uDN @world

Eğer değerini değiştirmek istediğiniz işlem zaten çalışıyor ise, renice kullanabilirsiniz. Örneğin PID numarası 219 olan işlemin nice değerini 5 artırmak için:

    # renice +5 219

Sinyal Göndermek (ve İşlemleri Sonlandırmak)

Bazı işlemler kendisine sinyal göndermenizi destekler. Sinyaller, sistem seviyesinde işlemleri uyarırlar ve 0 ile 64 arasında bir değere sahiptirler. kill komutu ile bir işleme sinyal gönderebilir ve kullanılabilir sinyallerin listesini alabiliriz:

    $ kill -l
     1) SIGHUP       2) SIGINT        3) SIGQUIT      4) SIGILL
     5) SIGTRAP      6) SIGABRT       7) SIGBUS       8) SIGFPE
     9) SIGKILL     10) SIGUSR1      11) SIGSEGV     12) SIGUSR2
    13) SIGPIPE     14) SIGALRM      15) SIGTERM     16) SIGSTKFLT
    17) SIGCHLD     18) SIGCONT      19) SIGSTOP     20) SIGTSTP
    21) SIGTTIN     22) SIGTTOU      23) SIGURG      24) SIGXCPU
    25) SIGXFSZ     26) SIGVTALRM    27) SIGPROF     28) SIGWINCH
    29) SIGIO       30) SIGPWR       31) SIGSYS      34) SIGRTMIN
    35) SIGRTMIN+1  36) SIGRTMIN+2   37) SIGRTMIN+3  38) SIGRTMIN+4
    39) SIGRTMIN+5  40) SIGRTMIN+6   41) SIGRTMIN+7  42) SIGRTMIN+8
    43) SIGRTMIN+9  44) SIGRTMIN+10  45) SIGRTMIN+11 46) SIGRTMIN+12
    47) SIGRTMIN+13 48) SIGRTMIN+14  49) SIGRTMIN+15 50) SIGRTMAX-14
    51) SIGRTMAX-13 52) SIGRTMAX-12  53) SIGRTMAX-11 54) SIGRTMAX-10
    55) SIGRTMAX-9  56) SIGRTMAX-8   57) SIGRTMAX-7  58) SIGRTMAX-6
    59) SIGRTMAX-5  60) SIGRTMAX-4   61) SIGRTMAX-3  62) SIGRTMAX-2
    63) SIGRTMAX-1  64) SIGRTMAX

Komutun ismi (kill - öldürmek) en bilinen kullanım alanı ile ilgili ipucu verebilir. Genelde direkt olarak iletişim kurulamayan programları sonlandırmak için kullanılır. Bu iş için uygulamaya 15 sinyali (SIGTERM) göndermek gerekmektedir. kill komutu, özel olarak sinyal sayısı belirtilmez ise 15 numarayı gönderir. Eğer işleminiz bu sinyali dinlemiyorsa veya tepkisiz hale geldiyse, 9 numaralı ölümcül sinyali gönderebilirsiniz: SIGKILL. Bu sinyal uygulamaya ulaşmaz, çekirdekten uygulamanın anında sonlandırılmasını ister:

    $ kill -9 219

Alıştırmalar

  1. Çalışan bir işlemin ID’sini (PID) hangi şekillerde alabiliriz?
  2. Servis olarak çalışmayan bir işlemi, oturumu sonlandırdığınız halde arkaplanda çalışmaya devam ettirebilmek için ne yapabiliriz?
  3. < defunct > işlem nedir?
  4. “ps aux” komutunun çıktısını inceleyin.

Kaynaklar