Por que o bash 4.3 continua alocando memória em um script

4

Por que esse script de shell consome gradualmente mais memória no bash? Não estou usando nenhuma variável local e, embora o valor de cpid esteja mudando a cada iteração, porque ls sai imediatamente, mas nunca deve ficar muito grande.

O script de shell em questão apenas monitora um subprocesso e verifica se ele está ativo. Este script é denominado run-always

set -euf

# monitor a child process
# see if it's up

cpid=
while : ; do
    # if cpid isn't set, spawn child
    if [ -z "$cpid" ]; then
       "$@" &
       cpid="$!"
    fi

    # if child isn't active unset cpid
    if ps -o pid= -p "$cpid"; then
        :
    else
        cpid=
    fi

    sleep 1
done

Se eu usá-lo com um processo que sai imediatamente (como ls ), obtemos o seguinte uso de memória quando eu executo o script com dash run-always ls

4476kb e nunca cresce.

Este é o comando que estou usando para obter o uso de memória uma vez por segundo no Linux ... provavelmente há uma maneira de obter o uso de memória e pico de memória diretamente de ps , mas isso faz o trabalho.

 while : ; do cat /proc/"$(ps a | grep run-always | grep -v grep | awk '{print $1}')"/status | grep -i 'vmsize\|vmpeak' ; sleep 1; done

Quando executo o script acima com dash , o uso de memória nunca cresce, ele fica em uma constante 4476kb na minha máquina.

No entanto, quando eu uso o bash ( bash run-always ls ), a cada dez segundos ele aloca outros kilobytes de memória e nunca os libera.

Por que o bash está fazendo isso?

Exemplo de saída:

VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16676 kB
VmSize:    16676 kB
VmPeak:    16680 kB
VmSize:    16680 kB
VmPeak:    16680 kB
VmSize:    16680 kB
VmPeak:    16680 kB
VmSize:    16680 kB
VmPeak:    16680 kB
VmSize:    16680 kB
VmPeak:    16680 kB
VmSize:    16680 kB
VmPeak:    16680 kB
VmSize:    16680 kB
VmPeak:    16680 kB
VmSize:    16680 kB
VmPeak:    16680 kB
VmSize:    16680 kB
VmPeak:    16680 kB
VmSize:    16680 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16684 kB
VmSize:    16684 kB
VmPeak:    16688 kB
VmSize:    16688 kB
VmPeak:    16688 kB
VmSize:    16688 kB
VmPeak:    16688 kB
VmSize:    16688 kB
VmPeak:    16688 kB
VmSize:    16688 kB
VmPeak:    16688 kB
VmSize:    16688 kB
VmPeak:    16688 kB
VmSize:    16688 kB
VmPeak:    16688 kB
VmSize:    16688 kB
VmPeak:    16688 kB
VmSize:    16688 kB
VmPeak:    16688 kB
VmSize:    16688 kB
VmPeak:    16688 kB
VmSize:    16688 kB
VmPeak:    16692 kB
VmSize:    16692 kB
    
por Gregory Nisbet 21.04.2016 / 23:13

2 respostas

1

Bash salva cada processo em segundo plano em uma tabela de tarefas ativas. Como você gera novos trabalhos sem verificar explicitamente os antigos, a tabela aumenta potencialmente sem limite. O problema desaparece se você disown o processo após o plano de fundo ou verificar o status de saída usando jobs antes de iniciar o próximo processo em segundo plano.

Por exemplo, esta versão do seu script não aumenta o uso de memória:

set -euf

# monitor a child process
# see if it's up

cpid=
while : ; do
    # if cpid isn't set, spawn child
    if [ -z "$cpid" ]; then
       "$@" &
       disown $!       # Don't waste memory on this red-headed child
       cpid="$!"
    fi

    # if child isn't active unset cpid
    if ps -o pid= -p "$cpid"; then
        :
    else
        cpid=
    fi

    sleep 1
done
    
por 28.12.2017 / 19:47
1

Como você já descobriu que esse problema não aparece com o traço, parece óbvio que há uma alta probabilidade de que isso seja causado por um bug.

Ele também cresce se você estiver usando o bash-3.x mas muito lentamente - ainda mais rápido que com outros shells.

Eu recomendo que você faça um relatório de erros contra sua versão do bash.

BTW: Fiz alguns testes e há apenas dois shells nos quais não há crescimento algum, independentemente de quanto tempo você espera: mksh e o original Bourne Shell que ainda não foi convertido para usar malloc () em vez de sbrk ().

Todas as outras camadas crescem muito lentamente.

    
por 22.04.2016 / 00:00