Processi in Linux: ps, top, htop, kill, segnali e nice
I processi Linux si osservano con ps aux (istantanea), top e htop (elenco aggiornato con il carico). Si terminano con kill PID, che di default invia un SIGTERM gentile; kill -9 (SIGKILL) serve solo se il processo non reagisce. La priorità si imposta con nice all'avvio e con renice per un processo già in esecuzione, nell'intervallo da -20 a 19.
Ogni programma in esecuzione su Linux è un processo, con un proprio numero PID, un proprietario, uno stato e una priorità. I processi si osservano con ps, top e htop, si terminano con kill, e la loro priorità si modifica con nice e renice. Qui sotto vediamo come leggere l'output di questi comandi, quali segnali inviare e perché kill -9 non dovrebbe essere il primo riflesso.
Cos'è un processo e il PID
Un processo è un programma nel momento in cui viene eseguito: codice, memoria, file aperti e un insieme di attributi. Il kernel assegna a ogni processo un identificatore univoco, il PID, e ne registra anche il PPID, cioè il numero del processo padre che lo ha avviato. Il primo processo del sistema, con PID 1, è di solito systemd, ed è l'antenato di tutti gli altri.
Un nuovo processo nasce in due passi. Prima il padre chiama fork() e ottiene una propria copia, poi la copia chiama execve() e sostituisce il proprio codice con quello del nuovo programma. Quando nel terminale digiti ls, bash fa esattamente questo e attende la fine del figlio con wait().
$ echo $$ # PID della shell corrente
4182
$ ps -o pid,ppid,cmd -p $$
PID PPID CMD
4182 4170 -bash
Come vedere i processi con ps
ps fa un'istantanea: mostra i processi nel momento in cui viene lanciato e poi termina. Senza argomenti mostra solo i processi del terminale corrente, quindi nella pratica si usa quasi sempre una di due varianti.
$ ps aux | head -5
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.3 168540 12780 ? Ss 09:12 0:03 /sbin/init
root 2 0.0 0.0 0 0 ? S 09:12 0:00 [kthreadd]
www-data 1532 1.2 2.1 412308 86420 ? S 09:15 1:47 php-fpm: pool www
postgres 1610 0.4 3.8 221004 154312 ? Ss 09:15 0:31 postgres: checkpointer
Qui a significa processi di tutti gli utenti, u formato dettagliato con il proprietario, x include i processi senza terminale (i demoni). La sintassi alternativa in stile System V è ps -ef: mostra il PPID, utile per capire chi ha avviato chi.
| Colonna | Significato |
|---|---|
PID | identificatore del processo |
%CPU, %MEM | quota di processore e di memoria fisica |
VSZ | memoria virtuale in KB (inclusa quella non caricata in RAM) |
RSS | memoria fisica effettivamente occupata, in KB |
STAT | stato del processo (R, S, D, Z, T) e flag |
TIME | tempo di processore complessivo, non il tempo di esecuzione |
Trucchi utili con ps
# top 10 per memoria
ps aux --sort=-%mem | head -11
# top 10 per processore
ps aux --sort=-%cpu | head -11
# colonne personalizzate
ps -eo pid,ppid,user,ni,stat,etime,cmd
# albero dei processi
ps -ef --forest
pstree -p
# trovare il PID dal nome
pgrep -a nginx
pidof nginx
Errore classico: cercare un processo con ps aux | grep nginx e ritrovarsi nell'output lo stesso grep. Usa pgrep oppure il trucco grep [n]ginx, che non corrisponde alla propria riga di comando.
Stati dei processi: R, S, D, Z, T
La lettera nella colonna STAT non è un dettaglio: è lo stato reale del processo. Da essa dipende come interpretare il carico e se kill servirà a qualcosa.
| Codice | Stato | Cosa significa in pratica |
|---|---|---|
R | Running | in esecuzione oppure in coda per la CPU |
S | Interruptible sleep | in attesa di un evento (rete, input, timer); è lo stato normale della maggior parte dei processi |
D | Uninterruptible sleep | in attesa di I/O dentro il kernel, i segnali non vengono consegnati |
Z | Zombie | terminato, ma il padre non ha ancora letto il suo codice di uscita |
T | Stopped | sospeso da un segnale SIGSTOP o da Ctrl+Z |
Utili anche i caratteri aggiuntivi dopo la lettera: s — leader di sessione, + — processo in primo piano nel terminale, < — priorità elevata, N — priorità ridotta, l — multithread.
Processo nello stato D
Un processo in D si trova dentro una chiamata di sistema e aspetta, ad esempio, la risposta di un disco o di un NFS bloccato. Non riceve alcun segnale, nemmeno SIGKILL. Quindi kill -9 qui è inutile: bisogna cercare la causa dell'attesa, osservando iostat, dmesg e lo stato dello storage di rete.
Processi zombie
Uno zombie è già morto: non consuma CPU né memoria, occupa solo una riga nella tabella dei processi. Non si può ucciderlo, perché è già terminato. Scompare quando il padre chiama wait(), oppure quando il padre stesso termina e lo «adotta» il PID 1.
# trovare gli zombie e i loro padri
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/'
Un singolo zombie è innocuo. Se ce ne sono centinaia e il numero cresce, c'è un errore nel programma padre: va corretto oppure riavviato.
top: processi e carico in tempo reale
top mostra lo stesso elenco, ma lo aggiorna ogni pochi secondi e presenta un riepilogo del sistema. È il primo comando da lanciare quando «il server rallenta».
top - 14:21:07 up 12 days, 3:02, 2 users, load average: 1.84, 1.20, 0.95
Tasks: 213 total, 2 running, 211 sleeping, 0 stopped, 0 zombie
%Cpu(s): 23.1 us, 4.2 sy, 0.0 ni, 70.3 id, 1.9 wa, 0.0 hi, 0.5 si, 0.0 st
MiB Mem : 7821.4 total, 412.6 free, 3105.8 used, 4303.0 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 4398.2 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1532 www-data 20 0 412308 86420 14212 R 38.2 1.1 1:47.31 php-fpm
1610 postgres 20 0 221004 154312 148900 S 6.0 1.9 0:31.08 postgres
Nella riga %Cpu(s) la cosa più importante è: us — codice utente, sy — kernel, id — inattività, wa — attesa del disco. Un valore alto di wa con il processore libero indica chiaramente un collo di bottiglia nell'I/O.
Tasti rapidi di top
| Tasto | Azione |
|---|---|
P / M | ordinamento per CPU / per memoria |
1 | mostra ogni core separatamente |
c | riga di comando completa |
u | filtro per utente |
k | invia un segnale a un processo |
r | cambia il nice del processo |
H | mostra i thread |
q | uscita |
Per script e log è utile la modalità batch: top -b -n 1 | head -20 stampa un'istantanea senza interattività. Per seguire un processo specifico usa top -p 1532.
Load Average: è una coda, non una percentuale
I tre numeri del load average indicano la lunghezza media della coda negli ultimi 1, 5 e 15 minuti. In Linux vi rientrano i processi nello stato R e D, mentre il sonno normale S no. Il valore LA va confrontato con il numero di core (nproc): su 4 core, il valore 4 significa carico pieno, mentre 12 significa una coda tre volte superiore alle capacità.
Se il LA è alto ma il processore è inattivo, cerca i processi in D: ps -eo stat,pid,cmd | grep '^D'. Quasi sempre si tratta di un disco lento o di uno storage di rete.
htop: una comoda alternativa a top
htop mostra le stesse informazioni, ma con indicatori colorati per ogni core, scorrimento, supporto del mouse e albero dei processi. Di solito va installato: sudo apt install htop oppure sudo dnf install htop.
F3oppure/— cerca un processo per nome;F4— filtro che lascia visibili solo le corrispondenze;F5oppuret— albero «padre — figli»;F6— scelta della colonna di ordinamento;F7/F8— diminuisce o aumenta il nice;F9— menu dei segnali per il processo selezionato;Space— seleziona più processi per un'azione di massa.
Sui server dove non si può installare nulla basta top: anche lì ci sono tutte le operazioni fondamentali.
Come terminare un processo: kill e i segnali
Il comando kill non «uccide» in senso stretto, ma invia un segnale al processo. Cosa succede dopo dipende dal segnale e da come il programma lo gestisce.
| Segnale | Numero | Scopo |
|---|---|---|
SIGHUP | 1 | caduta del terminale; molti demoni rileggono la configurazione |
SIGINT | 2 | interruzione, come Ctrl+C |
SIGKILL | 9 | terminazione forzata dal kernel, non può essere intercettata |
SIGTERM | 15 | richiesta di terminare in modo corretto; è il default di kill |
SIGSTOP | 19 | sospende il processo, non può essere intercettato |
SIGCONT | 18 | riprende un processo sospeso |
SIGTSTP | 20 | sospensione dal terminale, Ctrl+Z |
I numeri valgono per x86 e ARM; l'elenco completo si ottiene con kill -l. Indicare il segnale per nome è più affidabile che per numero.
kill 1532 # SIGTERM
kill -TERM 1532 # lo stesso, esplicito
kill -HUP $(pidof nginx) # rileggere la configurazione
kill -STOP 1532; kill -CONT 1532
kill -0 1532 && echo "il processo è vivo"
Il segnale 0 non invia niente, ma verifica che il processo esista e che tu abbia il diritto di scrivergli: utile negli script.
Perché non cominciare da kill -9
SIGTERM dà al programma la possibilità di chiudere i file, svuotare i buffer, rimuovere i file di lock e completare correttamente le transazioni. SIGKILL interrompe tutto all'istante: i dati non scritti vanno persi, i file temporanei restano, e un database può entrare in ripristino al successivo avvio.
La sequenza corretta è questa:
- Invia
kill PID(SIGTERM). - Attendi 5–30 secondi, controllando con
kill -0 PID. - Solo se il processo è ancora vivo e non è nello stato
D—kill -9 PID.
Per i servizi gestiti da systemd è meglio non toccare il PID a mano: systemctl stop invia da solo SIGTERM, attende il timeout e poi ricorre a SIGKILL.
pkill e killall: per nome
pkill -f "python worker.py" # per riga di comando completa
pkill -u alice # tutti i processi dell'utente
killall -TERM node # tutti i processi chiamati node
pgrep -l -f worker # prima verifica cosa verrà colpito
Prima di un pkill di massa esegui sempre pgrep con lo stesso pattern: -f corrisponde a qualsiasi parte della riga di comando e può facilmente colpire processi non voluti.
I segnali si possono inviare solo ai propri processi; per quelli altrui serve sudo. L'errore Operation not permitted significa proprio questo.
Priorità dei processi: nice e renice
Il valore nice indica allo scheduler quanto un processo debba cedere il passo agli altri per il processore. L'intervallo va da -20 (priorità massima) a 19 (cede a tutti), il valore predefinito è 0. In top compare nella colonna NI, mentre PR è la priorità interna derivata.
# avviare un'attività pesante con priorità ridotta
nice -n 10 tar czf backup.tar.gz /var/www
# abbassare la priorità di un processo in esecuzione
renice -n 15 -p 1532
# alzare la priorità (solo root)
sudo renice -n -5 -p 1610
# tutti i processi di un utente
sudo renice -n 10 -u alice
Un utente normale può solo abbassare la priorità dei propri processi; i valori negativi sono riservati a root. È importante conoscere il limite di nice: incide solo sulla CPU. Se un'attività rallenta il sistema tramite il disco, usa ionice -c3 comando — classe idle, che riceve il disco solo quando nessun altro lo richiede.
Processi in background e job della shell
Un comando si può avviare in background aggiungendo &, oppure sospendere con Ctrl+Z. La shell tiene un elenco di job, gestiti con i comandi interni.
$ long_task &
[1] 5120
$ jobs
[1]+ Running long_task &
$ fg %1 # riportare in primo piano
^Z # sospendere (SIGTSTP)
$ bg %1 # proseguire in background
Chiudendo il terminale, la shell invia SIGHUP ai job, che terminano. Per far sopravvivere il processo all'uscita, avvialo con nohup comando &, staccalo con disown oppure usa tmux. Per un'attività permanente è meglio trasformarla in un servizio systemd.
Scenari tipici di diagnostica
Chi consuma il processore
top -o %CPU # oppure P dentro top
ps -eo pid,user,%cpu,etime,cmd --sort=-%cpu | head
Se un processo consuma CPU senza motivo, abbassagli prima la priorità con renice: è un'operazione sicura e lascia il tempo di capire cosa succede.
Chi occupa una porta
sudo ss -ltnp | grep :8080
sudo lsof -i :8080
L'output riporta il PID, e da lì in /proc/PID/ si trovano l'eseguibile (exe), la directory di lavoro (cwd) e gli argomenti (cmdline).
Il processo è sparito all'improvviso
Una causa frequente è l'OOM Killer, che termina i processi quando la memoria si esaurisce. Verifica con dmesg -T | grep -i oom oppure journalctl -k | grep -i "killed process".
Conclusioni
Per lavorare con i processi su Linux bastano pochi comandi: ps aux per un'istantanea, top e htop per il monitoraggio, kill con il segnale giusto per terminare e nice/renice per le priorità. Osserva lo stato del processo prima di agire: gli zombie e i processi in D non si risolvono con i segnali. E inizia sempre con SIGTERM, lasciando kill -9 per i casi estremi. Processi, memoria, load average e chiamate di sistema sono trattati in modo approfondito, con esempi pratici, nel corso Linux.
Domande frequenti
Qual è la differenza tra ps aux e ps -ef?
Sono due sintassi dello stesso comando: aux è lo stile BSD con le colonne %CPU, %MEM e STAT, -ef è lo stile System V con la colonna PPID. In entrambi i casi l'elenco dei processi è lo stesso, cioè tutti i processi del sistema.
Come faccio a sapere quanti processi sono in esecuzione nel sistema?
Il modo più semplice è guardare la riga Tasks in top oppure eseguire ps -e --no-headers | wc -l. Il numero dei thread si ottiene con ps -eLf --no-headers | wc -l.
Perché un processo non termina nemmeno con kill -9?
O è nello stato D e attende l'I/O nel kernel, oppure è uno zombie già terminato. Nel primo caso cerca il problema sul disco o sullo storage di rete, nel secondo correggi o riavvia il processo padre.
Cosa succede se termino il processo con PID 1?
Il kernel protegge init: i segnali ordinari, incluso SIGKILL inviato da un utente, non gli vengono consegnati se non li gestisce. Se però init dovesse terminare, il sistema andrebbe in kernel panic.
Come limito la memoria usata da un processo?
Per un servizio systemd imposta MemoryMax= nel file unit; per un'esecuzione occasionale usa systemd-run --scope -p MemoryMax=500M comando. Funziona tramite i cgroup ed è più affidabile del vecchio ulimit -v.
Questo argomento è trattato in modo approfondito, con pratica, nel corso «Linux: с нуля до уверенного администрирования».
Vai al corso