qual é o propósito da supercomprometimento de memória no Linux?

5

Eu sei sobre supercomprometimento de memória e eu não gosto muito dele e geralmente o desabilito.

Um programa bem escrito poderia usar malloc (ou mmap , que é frequentemente usado por malloc ) mais memória do que a disponível e travar ao usá-la. Sem comprometimento excessivo de memória, esse malloc ou mmap falharia e o programa bem escrito detectaria essa falha. O programa mal escrito (usando malloc sem verificações contra falha) falharia ao usar o resultado de uma falha malloc .

É claro que espaço de endereçamento virtual (que é estendido por mmap , então por malloc ) não é o mesmo como RAM (RAM é um recurso gerenciado pelo kernel, consulte este ; processo tem seu espaço de endereço virtual inicializado por execve (2) e estendido por mmap & sbrk , então não consuma < em> diretamente RAM, apenas memória virtual ).

Observe que a otimização do uso de RAM pode ser feita com madvise (2) (que poderia dar uma dica, usando MADV_DONTNEED para o kernel trocar algumas páginas no disco), quando realmente necessário. Os programas que desejam algum comprometimento excessivo podem usar o mmap (2) com MAP_NORESERVE . Meu entendimento de supercomprometimento de memória é como se todo mapeamento de memória (por execve ou mmap ) estivesse usando implicitamente MAP_NORESERVE

Minha percepção é que é simplesmente útil para programas com muito bugs. Mas IMHO um desenvolvedor real deve sempre verificar a falha de malloc , mmap e funções de alteração de espaço de endereço virtual relacionadas (por exemplo, aqui ). E a maioria dos programas de software livre cujo código-fonte eu estudei tem essa verificação, talvez como alguma função xmalloc ....

Existem programas da vida real, por ex. empacotados em distribuições típicas do Linux, que realmente precisam e estão usando o supercomprometimento de memória de uma maneira sã e útil? Eu não conheço nenhum deles!

Quais são as desvantagens de desativar o comprometimento excessivo de memória? Muitos Unixes antigos (por exemplo, SunOS4, SunOS5 do século anterior) não o tinham, e IMHO seu malloc (e talvez até o desempenho geral do sistema completo, malloc -wise) não foi muito pior (e melhorias desde então) não estão relacionados com a supercomprometimento de memória).

Acredito que o excesso de memória é um erro de programação para programadores preguiçosos.

    
por Basile Starynkevitch 02.05.2018 / 18:56

3 respostas

8

O motivo da supercomprometimento é evitar a subutilização da RAM física. Há uma diferença entre quanto de memória virtual um processo alocou e quanto dessa memória virtual foi realmente mapeada para quadros de página física. Na verdade, logo após o início de um processo, ele reserva muito pouca memória RAM. Isso ocorre devido à demanda de paginação: o processo tem um layout de memória virtual, mas o mapeamento do endereço de memória virtual para um quadro de página físico não é estabelecido até que a memória seja lida ou gravada.

Normalmente, um programa nunca usa todo o espaço da memória virtual e as áreas de memória tocadas variam durante a execução do programa. Por exemplo, os mapeamentos para quadros de páginas contendo códigos de inicialização que são executados somente no início da execução podem ser descartados e os quadros de páginas podem ser usados para outros mapeamentos.

O mesmo se aplica aos dados: quando um programa chama malloc , ele reserva um espaço de endereço virtual contíguo suficientemente grande para armazenar dados. No entanto, os mapeamentos para quadros de páginas físicas não são estabelecidos até que as páginas sejam realmente usadas, se alguma vez . Ou considere a pilha do programa: cada processo obtém uma área de memória virtual contígua razoavelmente grande reservada para a pilha (normalmente 8 MB). Um processo geralmente usa apenas uma fração desse espaço de pilha; programas pequenos e bem comportados usam ainda menos.

Um computador Linux normalmente possui muitos processos heterogêneos em execução em diferentes estágios de suas vidas úteis. Estatisticamente, em qualquer momento, eles não precisam coletivamente de um mapeamento para cada página virtual que foram atribuídos (ou serão atribuídos posteriormente na execução do programa).

Um esquema estritamente não excessivo criaria um mapeamento estático de páginas de endereço virtuais para quadros de página de RAM física no momento em que as páginas virtuais são alocadas. Isso resultaria em um sistema que pode executar muito menos programas simultaneamente, porque muitos quadros de página RAM seriam reservados para nada.

Não nego que a supercomprometimento de memória tenha seus perigos e possa levar a situações de falta de memória que são complicadas de se lidar. É tudo sobre encontrar o compromisso certo.

    
por 02.05.2018 / 23:23
3

Você diz isso como se a preguiça não fosse considerada uma virtude na programação:).

Grandes quantidades de software são otimizadas para simplicidade e capacidade de manutenção, com condições de pouca memória sobreviventes como uma prioridade muito baixa. É comum tratar a falha de alocação como fatal. Sair do processo que esgota a memória evita uma situação em que não há memória livre, e o sistema não pode progredir sem alocar mais memória ou complexidade na forma de pré-alocação abrangente.

Observe como a diferença está entre verificar alocações e morrer, ou não verificar e travar. Não seria justo culpar o overcommit em programadores simplesmente não se preocupando em verificar se malloc () teve sucesso ou falhou.

Existe apenas uma pequena quantidade de software em que você pode confiar para continuar "corretamente" em caso de alocações mal-sucedidas. O kernel deve geralmente ser esperado para sobreviver. O sqlite tem um teste notoriamente robusto que inclui testes sem memória, especificamente porque se destina a suportar vários pequenos sistemas embarcados .

Como um caminho de falha não usado na operação normal, o manuseio de condições de pouca memória corretamente impõe uma sobrecarga significativa na manutenção e no teste. Se esse esforço não produzir um benefício proporcional, pode ser mais proveitoso ser gasto em outro lugar .

Quando isso é interrompido, também é comum ter casos especiais para grandes alocações, para lidar com as causas mais comuns de falha.

Permitir que uma certa taxa de supercomprometimento seja provavelmente melhor visualizada neste contexto. Faz parte do atual comprometimento padrão no Linux.

Note que a idéia de desativar o overcommit no nível do kernel e fornecer mais swap do que você deseja usar, também tem seus inimigos. A lacuna na velocidade entre a RAM e os discos rígidos rotativos cresceu com o tempo, de modo que, quando o sistema realmente usa o espaço de troca que você permitiu, pode ser mais frequentemente descrito como "paralisando".

    
por 03.05.2018 / 11:09
3

Concordo e votei na resposta de Johan Myréen, mas aqui estão mais explicações que podem ajudá-lo a entender o problema.

Você parece confundir a área de troca, ou seja, no espaço em disco destinado a armazenar menos RAM e memória virtual. O último é feito de uma combinação de áreas RAM e em áreas de disco.

Os processos estão reservando e usando a memória virtual. Eles não têm idéia sobre onde é armazenado. Quando eles precisam acessar alguns dados que não estão na RAM, processos (ou threads) são suspensos até que o kernel faça o trabalho para que a página de dados esteja disponível.

Quando há demanda de RAM, o kernel libera alguma RAM armazenando menos páginas de processo usadas na área de troca de disco.

Quando um processo reserva memória (ou seja, malloc e semelhantes), sistemas operacionais não supercomprometidos marcam partes não utilizadas da memória virtual como indisponíveis. Isso significa que, quando o processo que fez a alocação precisar acessar as páginas reservadas, elas terão a garantia de estar presentes.

A desvantagem é que o fato de a memória não ser utilizável por qualquer outro processo está impedindo que esses processos tenham suas páginas paginadas, portanto, a memória RAM é desperdiçada se esses processos estiverem inativos. Pior, se a soma das reservas for maior que o tamanho da área de troca, as páginas da RAM também serão reservadas para corresponder à reserva, apesar de não conter nenhum dado. Este é um cenário muito ruim, porque você terá RAM que é ambos inutilizável e não utilizados. Finalmente, o pior cenário possível é que uma reserva enorme não possa ser aceita porque não há mais memória virtual (swap + ram) disponível para ela. O processo que faz a reserva geralmente falha.

Por outro lado, sistemas operacionais supercomprometidos como o Linux apostam que não haverá falta de memória virtual a qualquer momento. Eles aceitam a maioria das reservas de memória (mas não irreais, isso pode ser mais ou menos sintonizado) e, em geral, isso permite uma melhor utilização dos recursos de RAM e troca.

Isso é semelhante a assentos com overbooking de companhias aéreas. Isso melhora a taxa de ocupação, mas alguns passageiros podem ficar insatisfeitos. Com sorte, as companhias aéreas apenas as reservam para outro voo e possivelmente as compensam enquanto o Linux simplesmente joga os passageiros mais pesados para fora do vôo ...

Para resumir, o Linux reserva a memória como uma maneira preguiçosa de "melhor esforço", enquanto vários outros sistemas operacionais garantem reservas.

Cenário de casos reais em que a supercomprometimento faz muito sentido é quando um programa que usa muita memória virtual faz um fork seguido por um exec.

Digamos que você tenha 4 GB de RAM, dos quais 3 GB estão disponíveis para memória virtual e 4 GB de troca. Há um processo reservando 4 GB, mas usando apenas 1 GB. Não há paginação para que o sistema tenha um bom desempenho. Em um SO não supercomprometido, esse processo não pode ser bifurcado, porque logo após a bifurcação, 4 GB a mais de memória virtual precisam ser reservados e restam apenas 3 GB.

No Linux, esta chamada de sistema bifurcada (ou clone) será concluída com sucesso (mas trapaceia sob a capa) e após o seguinte exec (se houver), esses 4 GB reservados mas não usados serão liberados sem nenhum dano.

    
por 03.05.2018 / 12:19

Tags