Os threads usam memória virtual ou memória real?

10

Eu estava tentando otimizar meu servidor Linux para lidar com 10.000 threads por processo, enquanto ele faz apenas 382 no momento. De acordo com este artigo, a seguinte fórmula é usada para descobrir o total de threads possíveis:

number of threads = total virtual memory / (stack size*1024*1024)

Isso significa que os threads armazenam todos os seus dados na memória virtual. E, até onde eu sei, a memória virtual é o espaço de troca em uma máquina Linux armazenada em disco rígido que RAM ou cache.

Portanto, minha pergunta é: nossos threads usam o disco rígido para armazenar e processar / armazenar seus dados.

Se sim, esse efeito não afeta o desempenho? Podemos melhorar o desempenho colocando-os na RAM ou no cache? Como?

Se não, como exatamente os threads funcionam?

Atualizar:

De acordo com a resposta do inútil , a memória virtual é um sistema que compreende aproximadamente:

  • memória física (RAM)
  • quaisquer arquivos de troca que você anexou
  • suporte de hardware para converter endereços virtuais em físicos e emitir falhas de página quando um endereço virtual não estiver disponível na memória física
  • (kernel) suporte de software para: gerenciar as tabelas de pesquisa usadas pelo hardware que lida com essas falhas de página, puxando as páginas da troca sob demanda

Assim, tudo o que está na memória virtual está coletivamente na RAM (Memória Real) e no Disco Rígido (Arquivos de Troca). E, como James explica em sua resposta, a decisão sobre Ram vs HDD é tomada pelo Kernel usando algoritmos como LRU.

dragosrsupercool
fonte
2
a menos que seu servidor tenha 10.000 CPU / Núcleos, você está desperdiçando seu tempo.
@JarrodRoberson: Algum por que é isso?
dragosrsupercool
3
10.000 threads não são uma boa maneira de escalar as coisas, é uma boa maneira de fazer um servidor rastrear; mais de 1 thread por CPU ou Core apenas fará o contexto do servidor alternar e rodar mais devagar e mais rápido.
Especificamente, quando você diz "tentando otimizar meu servidor Linux" - o que você está tentando otimizar? Se for taxa de transferência, é provável que um encadeamento por CPU com E / S sem multiplexação e sem bloqueio seja melhor.
Inútil

Respostas:

12

que eu saiba, memória virtual é espaço de troca em uma máquina Linux

Não, a memória virtual é um sistema que compreende aproximadamente:

  • memória física (RAM)
  • quaisquer arquivos de troca que você anexou
  • suporte de hardware para converter endereços virtuais em físicos e emitir falhas de página quando um endereço virtual não estiver disponível na memória física
  • suporte de software (kernel) para:
    • gerenciando as tabelas de pesquisa usadas por esse hardware
    • lidando com essas falhas de página, puxando as páginas da troca sob demanda

Cabe ao kernel garantir que a memória virtual que você deseja seja armazenada em cache na RAM quando desejar - a menos que você esteja gravando sua própria camada de VM no espaço do usuário (como os bancos de dados costumam fazer, iiuc), apenas não se preocupe.

Sem utilidade
fonte
Ok, então minha suposição de memória virtual estava errada. Enfim, uma pergunta rápida de acompanhamento. O desempenho máximo de threads totalmente carregado seria afetado se o SWAP Space fosse maior que a RAM?
dragosrsupercool
@dragosrsupercool: seu espaço de troca sempre será maior que a memória física, caso contrário, é necessário usar a memória virtual.
Bryan Oakley
11
@BryanOakley: Isso não é necessariamente verdade. Alguns SOs alocam uma página de troca para cada página virtual alocada (ou seja, a troca deve ser pelo menos tão grande quanto física). Outros SOs alocam uma página de troca apenas quando houver necessidade de mover uma página para fora da memória física (ou seja, a troca pode ser menor que a física). A vantagem do primeiro é que, se a alocação for bem-sucedida, a troca dessa memória será sempre bem-sucedida. A vantagem deste último é que você não precisa alocar pessimisticamente grandes arquivos de troca para explicar situações relativamente raras.
Mcmcc
11
@dragosrsupercool, o desempenho não será afetado pela quantidade de RAM, swap ou a proporção entre eles, a menos que você tenha pouca memória RAM e paginação. O sar pode falar sobre a atividade de paginação iirc (marcada: sar -Bno Linux).
Inútil
@ Useless: desejo aumentar o número de threads até utilizar completamente a RAM e não iniciar a paginação.
dragosrsupercool
14

Se o encadeamento estiver realmente em execução, a instrução atual e todas as variáveis ​​que o encadeamento estiver usando deverão estar na memória física.

A maioria (de fato quase todos) dos programas reside na memória virtual e, a maioria dos programas usa memória virtual para armazenamento de variáveis.

Endereços virtuais organizados em blocos chamados páginas (geralmente são blocos de 4096 ou 8192 bytes).

A qualquer momento, cada bloco de memória virtual é armazenado em algum lugar na memória real ou no disco no "espaço de troca" reservado para isso.

O código do seu programa lida com endereços virtuais, quando você ramifica para um endereço virtual ou solicita acesso ao armazenamento em um endereço virtual em que o sistema (geralmente no nível do hardware) localiza o local atual da solicitação de endereço e o mapeia para seu endereço virtual, se o endereço atualmente residir no disco, ele o pagina na memória real e mapeia o endereço.

Obviamente, quando toda a memória física estiver em uso, se alguma coisa for paginada, outra coisa deverá ser paginada, para que o sistema procure a página "Menos Utilizadas Recentemente" e a copie para o disco antes de copiar a página solicitada.

Nos sistemas modernos, existem várias otimizações e truques associados ao armazenamento virtual.

  • Os endereços são mapeados "por processo", portanto, por exemplo, todos os programas C em uma caixa Linux iniciam o processo "principal" no mesmo endereço.
  • Isso pode permitir que vários processos de 32 bits ocupem e usem muito mais que 4 GB em uma máquina, pois um endereço virtual de 32 bits pode ser mapeado para um endereço real de 64 bits.
  • Quando os processos terminam ou a memória está "livre", o sistema apenas marca as páginas como livres, elas nunca são copiadas de volta para o disco de troca.
  • Da mesma forma, quando um novo bloco de armazenamento é solicitado, o sistema apenas pega uma página livre na memória real; não, as E / S de disco ocorrem.
  • As funções de suspensão e hibernação forçam toda a memória a ser copiada para o espaço de troca, para que todos os processos atuais e o conteúdo da memória atual possam ser recriados na ativação.
James Anderson
fonte
3
Os "todos os programas C em uma caixa Linux iniciam [main] no mesmo endereço" parecem não levar em consideração a randomização do layout do espaço de endereço. Hoje em dia, isso é usado cada vez mais para impedir vários esquemas de ataque de esmagamento de pilha. Boa resposta caso contrário, então +1.
a CVn
7

Primeiro de tudo, você precisa ler mais sobre a memória do computador , porque parece não ter conhecimento nesse campo.

Um encadeamento de execução é a menor unidade de processamento que pode ser agendada por um sistema operacional. A implementação de threads e processos difere de um sistema operacional para outro, mas na maioria dos casos, um thread está contido dentro de um processo. Vários encadeamentos podem existir no mesmo processo e compartilhar recursos como memória, enquanto processos diferentes não compartilham esses recursos.

Portanto, os threads usarão a memória disponível - qualquer que seja o tipo disponível. A quantidade de threads que você pode iniciar depende do tamanho da memória e da quantidade de memória necessária por thread. Se o thread usar heap (não apenas a pilha), ele precisará de mais memória e, nesse caso, você poderá iniciar menos threads.

BЈовић
fonte
@VJonvic: +1 para explicação básica de threads.
dragosrsupercool
6

A resposta simples para sua pergunta é: eles usam memória virtual. tudo usa memória virtual, exceto alguns processos relacionados ao sistema operacional.

Por outro lado, quando seu thread (ou qualquer thread, em qualquer processo) está realmente em execução, ele está usando memória física. As páginas de memória associadas a esse processo são trocadas pela memória física, onde é o processador.

Bryan Oakley
fonte
3

A memória virtual é sua RAM mais seu espaço de troca. Virtual significa apenas que o endereço que seu programa vê é diferente do endereço que o chip de RAM vê. Se você precisar acessar a memória em troca, o sistema operacional a moverá primeiro para a RAM. Se você não deseja trocar, desative-o. Se você tem RAM suficiente, não precisa realmente disso.

Dito isto, a menos que você tenha um processador de 10.000 núcleos, aumentar para 10.000 threads não é realmente uma "otimização". Quando você tiver threads suficientes para consumir todos os núcleos, mais um ou dois para quando esses threads estiverem bloqueados, a adição de mais threads diminuirá o desempenho devido à sobrecarga de comutação e falhas de cache. Você ainda pode querer usar mais threads, se isso simplificar a lógica do programa, mas você estará trocando o desempenho.

Karl Bielefeldt
fonte
Sim, 10.000 é demais, pois meu servidor é uma máquina de núcleo único de 32 bits. Na verdade, os threads não são coisa de CPU total. Eles são threads de rastreador, portanto, seria como esperar pela resposta do servidor às vezes. O meu objetivo é garantir que a CPU esteja totalmente ocupada, mas não sobrecarregada ou sobrecarregada. Mas ainda não entendi como posso saber se a CPU está livre ou totalmente ocupada. Existe alguma ferramenta ou comando?
dragosrsupercool
Eu acho que você pode obter essas informações do topcomando.
Karl Bielefeldt
@KarlBieledeldt: sim, era exatamente isso que eu estava procurando .. Mais uma pergunta de acompanhamento: eu apenas vim com uma idéia de rastrear que, se de alguma forma, como um thread pode enviar solicitação de URLs enquanto o outro thread recebe a resposta do servidor, eu posso manter Alta utilização da CPU sem usar muitos threads. Isso é possível? Como enviar solicitação de um segmento enquanto recebe a resposta no outro segmento?
dragosrsupercool
2

otimizar meu servidor Linux para lidar com 10.000 threads por processo

Como outros explicaram, isso geralmente está errado. Um encadeamento é um recurso dispendioso , principalmente porque possui sua própria pilha de chamadas (normalmente, um megabyte) e porque é uma tarefa agendável pelo kernel. Os threads são ainda mais caros do que os descritores de arquivos abertos .

Leia Sistemas operacionais: Three Easy Pieces (livro didático disponível para download gratuito).

Como regra geral, você não deseja ter muitos threads, e certamente não muitos threads executáveis. O número de threads executáveis ​​geralmente deve ser no máximo o número de núcleos (ou um pequeno múltiplo disso), portanto, cerca de uma dúzia no máximo. O número de threads em um processo pode ser um pouco maior. Portanto, a menos que você tenha um servidor muito expansivo (com muitos soquetes e núcleos de processador), não deseja ter mais de uma dúzia de threads executáveis ​​e cem threads (a maioria deles ociosa) em seu processo (na área de trabalho) .

No Linux, threads e processos são muito semelhantes (já que ambos podem ser criados pelo clone (2) ) e ambos são tarefas agendadas pelo kernel. Na verdade, o agendador do kernel está agendando tarefas que podem ser threads dentro de algum processo com vários threads ou o thread principal único de um processo de thread único (nesse caso, você nomeará "processar" esse único thread) ou threads do kernel. Você provavelmente não deseja ter mais de mil tarefas agendáveis ​​no total no seu sistema de desktop.

No Linux, um processo é simplesmente um grupo de threads compartilhando o mesmo espaço de endereço virtual (e compartilhando outras coisas, como tabela de descritores de arquivos, etc ...). Alguns processos têm apenas um encadeamento.

Um espaço de endereço virtual é definido pela Wikipedia como

"o conjunto de intervalos de endereços virtuais que um sistema operacional disponibiliza para um processo"

(ver igualmente esta resposta explicando que a terminologia não é universal, e alguns documentação Microsoft usa um diferente e incompatível definição).

No Linux, proc (5) é útil para entender o espaço de endereço virtual de alguns processos. Tente ambos
cat /proc/self/mapse cat /proc/$$/mapsem um terminal. Veja também isso , e pmap (1) e ps (1) e top (1) .

Todos os programas de espaço do usuário estão executando em algum processo e usando memória virtual, portanto, todo processo tem seu próprio espaço de endereço virtual. A RAM física é um recurso gerenciado pelo kernel do Linux, e os aplicativos não têm acesso direto à RAM (exceto pelo mmap (2) -ing /dev/mem, consulte mem (4) ).

Portanto, um processo não usa diretamente RAM. Ele usa memória virtual e possui seu próprio espaço de endereço virtual. O kernel usa paginação para gerenciar páginas físicas da RAM e fornecer o espaço de endereço virtual e as abstrações do processo . A qualquer momento (mesmo quando seu processo estiver ocioso ou em execução), o kernel poderá paginar algumas páginas (por exemplo, trocá-las no disco). O kernel está configurando o MMU (e lidando com exceções de hardware de falta de página em algum manipulador de interrupções , buscando a página do disco ou propagando uma falha de segmentação para o processo, consulte o sinal (7) )

Você pode ter threads verdes acima dos threads do sistema (mas as bibliotecas de threads verdes são difíceis de implementar e depurar). Veja as goroutines usadas no Go para um exemplo chique. Veja também setcontext (3) .

Às vezes, seu sistema pode experimentar debulhar . Isso acontece quando a memória virtual total (necessária para todos os processos) excede, por um grande fator, a RAM física disponível. Em seguida, seu computador não responde. Leia sobre o tamanho do conjunto residente , paginação por demanda , conjunto de trabalho , comprometimento excessivo de memória , ASLR .

Veja também -for Linux- fork (2) , clone (2) , mmap (2) , madvise (2) , posix_fadvise (2) , mlock (2) , execve (2) , credenciais (7) , pthreads (7) , futex (7) , recursos (7) .

Basile Starynkevitch
fonte