Muitas vezes me confunde o fato de que, apesar de trabalhar profissionalmente com computadores há várias décadas e com o Linux há uma década, na verdade trato a maior parte da funcionalidade do sistema operacional como uma caixa preta, não muito diferente da mágica.
Hoje pensei no kill
comando e, embora o use várias vezes por dia (tanto em seu "normal" quanto em seu -9
sabor), devo admitir que não tenho absolutamente nenhuma idéia de como ele funciona nos bastidores.
Do meu ponto de vista, se um processo em execução estiver "travado", chamo kill
seu PID e, de repente, ele não está mais em execução. Magia!
O que realmente acontece lá? As páginas de manual falam sobre "sinais", mas certamente isso é apenas uma abstração. Enviar kill -9
para um processo não requer a cooperação do processo (como manipular um sinal), apenas o mata.
- Como o Linux impede o processo de continuar consumindo tempo de CPU?
- Ele foi removido da programação?
- Desconecta o processo de seus identificadores de arquivos abertos?
- Como é liberada a memória virtual do processo?
- Existe algo como uma tabela global na memória, em que o Linux mantém referências a todos os recursos ocupados por um processo, e quando eu "mato" um processo, o Linux simplesmente passa por essa tabela e libera os recursos um por um?
Eu realmente gostaria de saber tudo isso!
fonte
kill -9
Referência obrigatória .Respostas:
Você está presumindo que, porque alguns sinais podem ser capturados e ignorados, todos envolvem cooperação. Mas, de acordo com
man 2 signal
"os sinais SIGKILL e SIGSTOP não podem ser capturados ou ignorados". O SIGTERM pode ser capturado, e é por isso que a planíciekill
nem sempre é eficaz - geralmente isso significa que algo no manipulador do processo deu errado. 1 1Se um processo não define (ou não pode) definir um manipulador para um determinado sinal, o kernel executa uma ação padrão. No caso de SIGTERM e SIGKILL, é para finalizar o processo (a menos que seu PID seja 1; o kernel não será finalizado
init
) 2 significa que seus identificadores de arquivo estão fechados, sua memória retornada ao pool do sistema, seu pai recebe SIGCHILD, seu órfão os filhos são herdados pelo init, etc., como se tivesse chamadoexit
(vejaman 2 exit
). O processo não existe mais - a menos que acabe como um zumbi; nesse caso, ele ainda está listado na tabela de processos do kernel com algumas informações; isso acontece quando seu pai nãowait
e lide com essas informações corretamente. No entanto, os processos zumbis não têm mais memória alocada para eles e, portanto, não podem continuar sendo executados.Eu acho que é preciso o suficiente. A memória física é rastreada por página (uma página geralmente igual a um pedaço de 4 KB) e essas páginas são obtidas e retornadas a um pool global. É um pouco mais complicado, pois algumas páginas liberadas são armazenadas em cache, caso os dados contidos sejam necessários novamente (ou seja, dados que foram lidos em um arquivo ainda existente).
Claro, todos os sinais são uma abstração. Eles são conceituais, assim como "processos". Estou jogando semântica um pouco, mas se você quer dizer que o SIGKILL é qualitativamente diferente do SIGTERM, sim e não. Sim no sentido de que não pode ser capturado, mas não no sentido de que ambos são sinais. Por analogia, uma maçã não é laranja, mas maçãs e laranjas são, de acordo com uma definição preconcebida, ambas frutas. SIGKILL parece mais abstrato, pois você não pode pegá-lo, mas ainda é um sinal. Aqui está um exemplo de manipulação do SIGTERM, tenho certeza que você já viu isso antes:
Este processo irá dormir para sempre. Você pode executá-lo em um terminal e enviá-lo com o SIGTERM
kill
. Ele cospe coisas como:1066 é o meu UID. O PID será aquele do shell a partir do qual
kill
é executado ou o PID de kill se você o bifurcar (kill 25309 & echo $?
).Novamente, não faz sentido definir um manipulador para o SIGKILL porque ele não funcionará. 3 Se eu,
kill -9 25309
o processo será encerrado. Mas isso ainda é um sinal; o kernel possui informações sobre quem enviou o sinal , que tipo de sinal é etc.1. Se você não examinou a lista de possíveis sinais , consulte
kill -l
.2. Outra exceção, como Tim Post menciona abaixo, aplica-se a processos em suspensão ininterrupta . Eles não podem ser acordados até que o problema subjacente seja resolvido e, portanto, TODOS os sinais (incluindo o SIGKILL) foram adiados pela duração. Um processo não pode criar essa situação de propósito, no entanto.
3. Isso não significa que usar
kill -9
é a melhor coisa a se fazer na prática. Meu manipulador de exemplo é ruim no sentido em que não levaexit()
. O verdadeiro objetivo de um manipulador SIGTERM é dar ao processo a chance de fazer coisas como limpar arquivos temporários e sair voluntariamente. Se você usarkill -9
, ela não terá essa chance, então faça isso apenas se a parte "sair voluntariamente" parecer ter falhado.fonte
-9
porque esse é o verdadeiro problema, como quem deseja que este morra! ;)kill -9
certos processos vinculados de E / S não funcionará, pelo menos não imediatamente.kill -9
não pode ser capturado, um processo que o recebe não pode executar nenhuma limpeza (por exemplo, remover arquivos temporários, liberar memória compartilhada etc.) antes de sair. Portanto, usekill -9
(akakill -kill
) apenas como último recurso. Comece com umkill -hup
e / oukill -term
primeiro e depois usekill -kill
como golpe final.Cada processo é executado no horário agendado e, em seguida, é interrompido pelo timer do hardware, para fornecer o núcleo da CPU para outras tarefas. É por isso que é possível ter muito mais processos do que os núcleos da CPU ou até executar todo o sistema operacional com muitos processos em uma única CPU.
Depois que o processo é interrompido, o controle retorna ao código do kernel. Esse código pode então tomar uma decisão de não retomar a execução do processo interrompido, sem qualquer cooperação do lado do processo. O kill -9 pode acabar sendo executado em qualquer linha do seu programa.
fonte
Aqui está uma descrição idealizada de como a morte de um processo funciona. Na prática, qualquer variante Unix terá muitas complicações e otimizações adicionais.
O kernel possui uma estrutura de dados para cada processo que armazena informações sobre qual memória está mapeando, quais threads possui e quando são agendadas, quais arquivos ele abre etc. Se o kernel decide interromper um processo, faz uma anotação em a estrutura de dados do processo (e talvez na estrutura de dados de cada um dos encadeamentos) em que o processo deve ser morto.
Se um dos threads do processo estiver atualmente agendado em outra CPU, o kernel poderá acionar uma interrupção nessa outra CPU para fazer com que o thread pare de executar mais rapidamente.
Quando o planejador percebe que um encadeamento está em um processo que deve ser eliminado, não o agendará mais.
Quando nenhum dos threads do processo é agendado, o kernel começa a liberar os recursos do processo (memória, descritores de arquivo, ...). Cada vez que o kernel libera um recurso, ele verifica se o proprietário ainda possui recursos ativos. Quando o processo não tiver mais recursos ativos (mapeamento de memória, descritor de arquivo aberto,…), a estrutura de dados do próprio processo poderá ser liberada e a entrada correspondente poderá ser removida da tabela de processos.
Alguns recursos podem ser liberados imediatamente (por exemplo, desalocando a memória que não está sendo usada por uma operação de E / S). Outros recursos devem aguardar, por exemplo, os dados que descrevem uma operação de E / S não podem ser liberados enquanto a operação de E / S está em andamento (enquanto um DMA está em andamento, a memória que está acessando está em uso e o cancelamento do DMA exige contato com o periférico). O driver para esse recurso é notificado e pode tentar apressar o cancelamento; quando a operação não estiver mais em andamento, o driver concluirá a liberação desse recurso.
(A entrada na tabela de processos é na verdade um recurso que pertence ao processo pai, que é liberado quando o processo morre e o pai reconhece o evento .)
fonte