Como a cobrança de memória / confirmação funciona no Windows 10?


4

Essa pergunta é solicitada pelos seguintes fenômenos observados regularmente, para os quais gostaria de encontrar uma explicação:

  1. A consolidação atual é regularmente maior que o uso Físico + tamanho do arquivo de paginação. O que há com isso? Isso não deveria ser impossível? [Isso parece ser por causa da compactação. O que transforma a pergunta em: Por que não comprometer o limite e depois subir ou algo assim? Ou seja, qual é o ponto de compactação se não ajudar no uso da memória?]
  2. Às vezes, isso atinge níveis extremos onde a confirmação atual é mais do que o dobro do uso de memória física!
  3. Quando a carga de confirmação é preenchida e o Windows começa a me pedir para fechar as coisas, na maioria das vezes a memória física fica em torno de 60%. Isso parece terrivelmente ineficiente.

Isso está no Windows 10, conforme relatado pelo Process Explorer.

A pergunta final que eu gostaria de responder é: Posso renunciar a aumentar artificialmente meu arquivo de paginação para níveis em que meu SSD faminto por espaço está mal equipado para lidar apenas para que eu possa efetivamente utilizar minha memória física? (Ou mesmo que não estivesse tão cheio. Ou seja, eu gostaria de evitar sugestões como "Faça X / Y / Z no seu arquivo de paginação".)


A taxa de confirmação não tem nada a ver com o uso da RAM, o uso do arquivo de paginação ou qualquer combinação dos dois. É essencialmente um total de espaço de armazenamento potencial necessário, que pode estar na RAM ou no arquivo de paginação. O limite de confirmação é o tamanho da RAM + o tamanho do arquivo de paginação - uma pequena sobrecarga. Portanto, a única maneira de aumentar o limite de confirmação é aumentar o tamanho do arquivo de paginação ou adicionar RAM. Geralmente o primeiro é o mais fácil.
precisa saber é o seguinte

Você já disse isso, mas também disse que não tem tempo para elaborar mais. Por isso decidi perguntar aqui. Pelo que entendi, a carga de confirmação é "algo que, em algum momento, solicitou tanta memória e o sistema operacional já disse" e a carga de confirmação reflete isso, independentemente de a memória ser usada ou não. No entanto, isso não responde à maioria das perguntas que tenho. No mínimo, gostaria de uma resposta para a última pergunta e, idealmente, gostaria de obter uma imagem mais profunda e clara de como o gerenciamento de memória funciona no Windows.
martixy

Respostas:


8

Na verdade, isso é bastante simples quando você entende que a taxa de confirmação representa apenas o uso potencial - ainda que "garantido disponível, se você desejar" - de memória virtual, enquanto o "conjunto de trabalho privado" - que é essencialmente a RAM usada pela memória "confirmada" - é o uso real , assim como o espaço do arquivo de paginação. (Mas esse não é o uso completo da RAM, porque existem outras coisas que usam RAM).

Vamos supor que estamos falando de sistemas de 32 bits; portanto, o espaço máximo de endereço virtual disponível para cada processo é normalmente 2 GiB. (Não há diferença substancial em nenhum dos itens a seguir para sistemas de 64 bits, exceto que os endereços e tamanhos podem ser maiores - muito maiores.)

Agora, suponha que um programa em execução em um processo use o VirtualAlloc (uma API do Win32) para "confirmar" 2 MiB de memória virtual. Como seria de esperar, isso aparecerá como um adicional de 2 MiB de taxa de confirmação e há 2 MiB a menos de bytes de espaço de endereço virtual disponível no processo para alocações futuras.

Mas na verdade ainda não usará nenhuma memória física (RAM)!

A chamada do VirtualAlloc retornará ao chamador o endereço inicial da região alocada; a região estará em algum lugar no intervalo de 0x10000 a 0x7FFEFFFF, ou seja, cerca de 2 GiB. (O primeiro e o último 64KiB, ou 0x10000 em hex, de vas em cada processo nunca são atribuídos.)

Mas, novamente - ainda não há uso físico real de 2 MiB de armazenamento ! Nem na RAM, nem no arquivo de paginação. (Existe uma pequena estrutura chamada "Descritor de Endereço Virtual" que descreve o va inicial e o comprimento da região comprometida privada.)

Então aí está! A taxa de confirmação aumentou, mas o uso da memória física não.

Isso é fácil de demonstrar com a ferramenta sysinternals testlimit.

Algum tempo depois, digamos que o programa armazena algo (ou seja, uma operação de gravação na memória) nessa região (não importa onde). Ainda não há memória física embaixo de nenhuma região, portanto, esse acesso causará uma falha na página . Em resposta à qual o gerenciador de memória do sistema operacional, especificamente a rotina do manipulador de falhas de página (o "pager" para abreviar ... é chamado MiAccessFault), irá:

  1. alocar uma página física anteriormente "disponível"
  2. configure a entrada da tabela de páginas para a página virtual que foi acessada para associar o número da página virtual ao número da página física recém-atribuído
  3. adicione a página física ao conjunto de trabalho privado do processo
  4. e ignore a falha da página, fazendo com que a instrução que gerou a falha seja tentada novamente.

Você agora "culpou" uma página (4 KiB) no processo. E o uso da memória física aumentará de acordo e a RAM "disponível" diminuirá. A cobrança de confirmação não muda.

Algum tempo depois, se essa página não tiver sido referenciada por um tempo e a demanda por RAM for alta, isso poderá acontecer:

  1. o SO remove a página do conjunto de trabalho do processo.
  2. porque foi gravado desde que foi trazido para o conjunto de trabalho, é colocado na lista de páginas modificadas (caso contrário, ele entraria na lista de páginas em espera). A entrada da tabela de páginas ainda reflete o número físico da página da RAM, mas agora possui seu bit "válido" limpo, portanto, na próxima vez em que for referenciada, ocorrerá uma falha na página
  3. quando a lista de páginas modificadas atinge um limite pequeno, um thread do gravador de páginas modificado no processo "Sistema" é ativado e salva o conteúdo das páginas modificadas no arquivo de paginação (supondo que você tenha uma) e ...
  4. tira essas páginas da lista modificada e as coloca na lista de espera. Eles agora são considerados parte da RAM "disponível"; mas, por enquanto, eles ainda têm o conteúdo original de quando estavam em seus respectivos processos. Novamente, a taxa de confirmação não muda, mas o uso da RAM e o conjunto de trabalho privado do processo diminuem.
  5. As páginas da lista de espera agora podem ser redirecionadas , ou seja, usadas para outra coisa - como resolver falhas de página de qualquer processo no sistema ou usadas pelo SuperFetch. Contudo...
  6. Se um processo que perdeu uma página da lista modificada ou em espera tenta acessá-la novamente antes que a página física seja redirecionada (ou seja, ainda possui seu conteúdo original), a falha da página é resolvida sem a leitura do disco. A página é simplesmente recolocada no conjunto de trabalho do processo e a entrada da tabela de páginas é tornada "válida". Este é um exemplo de uma falha de página "flexível" ou "barata". Dizemos que as listas em espera e modificadas formam um cache de páginas em todo o sistema que provavelmente será necessário novamente em breve.

Se você não possui um arquivo de paginação, as etapas de 3 a 5 são alteradas para:

  1. As páginas estão na lista modificada, pois não há onde escrever seu conteúdo.

  2. As páginas estão na lista modificada, pois não há onde escrever seu conteúdo.

  3. As páginas estão na lista modificada, pois não há onde escrever seu conteúdo.

A etapa 6 permanece a mesma, uma vez que as páginas da lista modificada podem sofrer uma falha no processo que as perdeu como uma falha de página "flexível". Mas se isso não acontecer, as páginas permanecerão na lista modificada até o processo desalocar a memória virtual correspondente (talvez porque o processo termine).

Há outro uso do espaço de endereço virtual e da RAM, além da memória confirmada privada. Há um espaço de endereço virtual mapeado , para o qual o armazenamento de backup é um arquivo especificado em vez do arquivo de paginação. As páginas do vas mapeado que são paginadas são refletidas no uso da RAM, mas a memória mapeada não contribui para a cobrança de confirmação porque o arquivo mapeado fornece o armazenamento de backup: Qualquer parte da região mapeada que não esteja na RAM é simplesmente mantida no arquivo mapeado. Outra diferença é que a maioria dos mapeamentos de arquivos pode ser compartilhada entre processos; uma página compartilhada que já esteja na memória de um processo pode ser adicionada a outro processo sem precisar ir para o disco novamente (outra falha de página programável).

E há um vas não paginável , para o qual não há armazenamento de backup porque ele sempre reside na RAM. Isso contribui tanto para o uso da RAM relatado quanto para a "taxa de confirmação".

Parece que isso pode ocorrer por causa da compactação. O que transforma a pergunta em: Por que não comprometer o limite e depois subir ou algo assim? Ou seja, qual é o ponto de compactação se não ajudar no uso da memória?

Não. Não tem nada a ver com compactação. A compactação de memória no Windows é feita como uma etapa intermediária, em páginas que seriam gravadas no arquivo de paginação. Com efeito, permite que a lista de páginas modificada use menos RAM para conter mais itens, a algum custo no tempo da CPU, mas com uma velocidade muito maior que a E / S do arquivo de paginação (mesmo para um SSD). Como o limite de confirmação é calculado a partir do tamanho total da RAM + do arquivo de paginação, e não do uso da RAM + do arquivo de paginação, isso não afeta o limite de confirmação. O limite de confirmação não muda com a quantidade de RAM em uso ou com o que está em uso.

Quando a carga de confirmação é preenchida e o Windows começa a me pedir para fechar as coisas, na maioria das vezes a memória física fica em torno de 60%. Isso parece terrivelmente ineficiente.

Não é que o Windows esteja sendo ineficiente. São os aplicativos que você está executando. Eles estão cometendo muito mais problemas do que realmente estão usando.

O motivo de todo o mecanismo de "taxa de confirmação" e "limite de confirmação" é o seguinte: Quando ligo para o VirtualAlloc, devo verificar o valor de retorno para ver se é diferente de zero. Se for zero, significa que minha tentativa de alocação falhou, provavelmente porque faria com que a taxa de confirmação excedesse o limite de confirmação. Eu devo fazer algo razoável, como tentar cometer menos ou sair do programa de forma limpa.

Se o VirtualAlloc retornou diferente de zero, ou seja, um endereço, isso me diz que o sistema fez uma garantia - um compromisso, se você desejar - de que, no entanto, quantos bytes solicitados, começando nesse endereço, estarão disponíveis se eu optar por acessá-los; que existe um lugar para colocar tudo - RAM ou o arquivo de paginação. ou seja, não há razão para esperar qualquer tipo de falha no acesso a qualquer coisa nessa região. Isso é bom, porque não seria razoável esperar que eu verifique "funcionou?" em todo acesso à região alocada.

A analogia do "banco de empréstimo em dinheiro"

É um pouco como um banco que oferece crédito, mas estritamente em dinheiro. (Naturalmente, não é assim que os bancos reais funcionam.)

Suponha que o banco comece com um milhão de dólares em dinheiro na mão. As pessoas vão ao banco e solicitam linhas de crédito em quantidades variadas. Digamos que o banco me aprove uma linha de crédito de US $ 100.000 (eu crio uma região comprometida privada); isso não significa que algum dinheiro tenha saído do cofre. Se mais tarde eu contratar um empréstimo de, digamos, US $ 20.000 (acesso a um subconjunto da região), isso removerá o dinheiro do banco.

Mas, independentemente de eu contrair empréstimos ou não, o fato de ter sido aprovado por um máximo de US $ 100 mil significa que o banco poderá posteriormente aprovar apenas outros US $ 900.000 em linhas de crédito, total, para todos os seus clientes. O banco não aprovará crédito que exceda suas reservas de caixa (ou seja, não as comprometerá em excesso ), pois isso significaria que o banco poderia ter que recusar um devedor previamente aprovado, quando mais tarde surgisse com a intenção de obter seu empréstimo. . Isso seria muito ruim porque o banco já se comprometeu a permitir esses empréstimos e a reputação do banco despencaria.

Sim, isso é "ineficiente" em termos do uso desse dinheiro pelo banco. E quanto maior a disparidade entre as linhas de crédito aprovadas pelos clientes e os valores que eles realmente emprestam, menos eficiente ela é. Mas essa ineficiência não é culpa do banco; a culpa é dos clientes por solicitarem linhas de crédito tão altas, mas apenas contratar pequenos empréstimos.

O modelo de negócios do banco é que ele simplesmente não pode recusar um mutuário previamente aprovado quando ele aparecer para obter seu empréstimo - isso seria "fatal" para o cliente. É por isso que o banco mantém um controle cuidadoso de quanto do fundo de empréstimo foi "comprometido".

Suponho que expandir o arquivo de paginação, ou adicionar outro, seria como o banco sair e ganhar mais dinheiro e adicioná-lo ao fundo de empréstimo.

Se você deseja modelar a memória mapeada e não paginável nesta analogia ... não paginável é como um pequeno empréstimo que você deve contratar e manter fora quando abrir sua conta. (As estruturas não pagináveis ​​que definem cada novo processo.) A memória mapeada é como levar seu próprio dinheiro (o arquivo que está sendo mapeado) e depositá-lo no banco, retirando apenas partes dele por vez (paginando). Por que não paginar tudo de uma vez? Eu não sei, talvez você não tenha espaço em sua carteira para todo esse dinheiro. :) Isso não afeta a capacidade de outras pessoas pedirem emprestado dinheiro, porque o dinheiro que você depositou está em sua própria conta, não no fundo geral de empréstimos. Essa analogia começa a quebrar por aí, principalmente quando começamos a pensar em memória compartilhada, portanto, não exagere.

De volta ao sistema operacional Windows: O fato de você ter grande parte da sua RAM "disponível" não tem nada a ver com taxa de confirmação e limite de confirmação. Se você estiver próximo do limite de confirmação, isso significa que o sistema operacional já confirmou - ou seja, prometeu disponibilizar quando solicitado - essa quantidade de armazenamento. Ainda não precisa estar totalmente em uso para que o limite seja aplicado.

Posso renunciar a aumentar artificialmente meu arquivo de paginação para níveis em que meu SSD faminto por espaço está mal equipado para lidar apenas para que eu possa realmente utilizar efetivamente minha memória física? (Ou mesmo que não estivesse tão cheio. Ou seja, eu gostaria de evitar sugestões como "Faça X / Y / Z no seu arquivo de paginação".)

Desculpe, mas se você estiver com o limite de confirmação, há apenas três coisas que você pode fazer:

  1. Aumente sua RAM.
  2. Aumente o tamanho do seu arquivo de paginação.
  3. Execute menos coisas ao mesmo tempo.

Re opção 2: Você pode colocar um segundo arquivo de paginação em um disco rígido. Se os aplicativos não estiverem realmente usando toda a memória confirmada - o que aparentemente eles não estão, já que você está vendo tanta RAM livre - você não estará acessando muito esse arquivo de paginação, portanto, colocá-lo no disco rígido não prejudicar o desempenho. Se a lentidão de um disco rígido ainda o incomoda, outra opção é obter um segundo SSD pequeno e, portanto, barato, e colocar seu segundo arquivo de paginação nele. O único "showstopper" seria um laptop sem maneira de adicionar uma segunda unidade "não removível". (O Windows não permitirá que você coloque arquivos de paginação em unidades removíveis, como qualquer coisa conectada com USB.)

Aqui está outra resposta que escrevi que explica as coisas de uma direção diferente.

ps: Você perguntou sobre o Windows 10, mas devo dizer que funciona da mesma maneira em todas as versões da família NT, de volta ao NT 3.1 e nas versões de pré-lançamento também. O que provavelmente mudou foi a configuração padrão do Windows para o tamanho do arquivo de paginação, de 1,5x ou 1x de RAM para muito menor. Eu acredito que isso foi um erro.


11
+1 Esta é a resposta que eu gostaria de ter escrito. É assim que um sistema operacional moderno funciona. Antes dos SSDs, não havia problema porque não tínhamos muita RAM e tínhamos muito espaço no disco rígido. Agora que temos muita RAM e pouco espaço de armazenamento em massa em algumas máquinas, ter espaço suficiente no arquivo de paginação está se tornando um problema novamente. Faça disso uma prioridade para que sua máquina possa fazer uso eficiente da RAM.
David Schwartz

@DavidSchwartz: Eu já vi muitas de suas respostas sobre questões de MM, e devo dizer, vindo de você que é um grande elogio. Obrigado.
Jamie Hanrahan 02/02

A luz brilhou. Tudo (bem, a maioria) finalmente faz sentido. Leia esta e sua outra resposta, cada uma oferece novas idéias. Estou até tentado a tentar rastrear o livro. Notavelmente, eu fiz essa pergunta primeiro em nenhum outro senão no fórum interno (como sugerido pela troca de comentários sob a pergunta), mas ela parece um pouco morta. O que Davi disse também é verdade. Esta questão está um pouco atrasada, em certo sentido, porque eu tenho um novo SSD hoje em dia e posso pagar o arquivo de paginação extra, mas era um problema real com minha unidade extra-pequena anterior. ... Continua abaixo ...
martixy 02/02

... continuou de cima. Aliás, em minha própria pesquisa, descobri que essa não é a única maneira de fazer as coisas, pois o linux e muitos hipervisores de VM têm uma opção chamada "overcommit". Na verdade, parece que o Windows é minoria quando se trata de abordar a alocação de memória. Ah, e ao pensar nisso, criei mais ou menos a mesma analogia bancária. A coincidência é estranha.
28780 martelly

Mas essas opções de "supercomprometimento" nem sempre se referem a esse conceito específico. A memória virtual em um SO de uso geral, uma vez que o SO tenha dito "ok, a alocação foi bem-sucedida", deve agir para o programador exatamente como a memória física ... exceto pelo pequeno atraso que pode ocorrer de vez em quando quando ocorre uma falha de página . O problema de permitir a confirmação excessiva de todo o armazenamento físico que pode ser virtual é que a memória simples se refere a i = * j; pode gerar erros fatais , mesmo que eu esteja na sua pilha ej tenha sido retornado anteriormente como um ponteiro supostamente válido. (continuação ...)
Jamie Hanrahan 02/02
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.