Por que o gerenciamento de memória personalizado é necessário para ativos?

10

Praticamente todos os recursos relacionados à programação de jogos, especialmente jogos 3D de mundo aberto, falam sobre como você deve constantemente descarregar e recarregar ativos de e para o disco, memória do sistema e memória de vídeo. Eu posso entender isso nos consoles, pois eles têm esquemas de gerenciamento de memória muito simples que não conseguem lidar com nenhum potencial estouro.

No entanto, no PC, a situação é muito diferente. Há memória virtual fornecida pelo sistema operacional para a memória do sistema e o driver gráfico lida com a troca da CPU para a GPU. Então, por que não é suficiente carregar tudo de uma só vez e apenas ter que lidar com pré-busca e possivelmente garantir que não haja bloqueio enquanto um ativo necessário estiver sendo trocado?


Isso não quer dizer que tudo esteja sendo alocado ingenuamente usando algo parecido malloc. Tudo será mantido contíguo e coerente com o cache. É indiscutivelmente mais fácil tornar seu acesso à memória eficiente se você não precisar se preocupar com a entrada e saída de paginação manualmente de qualquer maneira ...


ATUALIZAR:

Depois de ler um pouco sobre as transferências de buffer assíncronas , fico com a idéia de que a maneira como o driver gráfico pode automaticamente paginar a entrada e a saída da memória é abaixo do ideal. Isso também vale para os recursos da CPU; ou seja, é melhor sempre gerenciar manualmente quando um determinado recurso deve ser carregado e descarregado, mesmo na presença de memória virtual?

jmegaffin
fonte
1
Você está assumindo que o conteúdo do ativo é armazenado na memória do sistema. Muitos dos seus dados de ativos serão armazenados na memória da GPU, o que é muito mais limitado.
Dado dado Games
Ao ler a resposta aqui , fico com a ideia de que os drivers OpenGL mantêm automaticamente todos os buffers / texturas na CPU também. No entanto, posso ver por que pode ser útil especificar essas transferências manualmente para aproveitar os uploads assíncronos .
jmegaffin
Tem certeza de que isso é relevante para o seu projeto de jogo? Não tenho certeza de ver o desafio técnico, apenas a solução. Se você não está enfrentando um desafio técnico, é difícil adaptar uma solução ou entendê-la.
AturSams 25/03
Eu estou querendo saber por que os mecanismos de jogo implementam sistemas complexos de armazenamento em cache de sistemas quando os sistemas / drivers operacionais já possuem sistemas de memória virtual disponíveis. Isso é relevante para mim porque estou escrevendo um jogo de mundo aberto, onde essas informações são muito importantes.
jmegaffin
Seu jogo está sofrendo de problemas de desempenho e a ferramenta de criação de perfil está mostrando que é por causa do acesso à memória? O problema dos jogos que contêm níveis abertos é que, em termos técnicos, isso se traduz em muitos dados. Quanto mais controle você tiver sobre esses dados, melhor será o desempenho. Por que não implementar o sistema mais eficiente para gerenciar dados? O desenvolvimento de jogos é muito competitivo e, quando você tem dinheiro para especialistas, não deixa pedra sobre pedra, procurando extrair mais detalhes e maior fps.
AturSams

Respostas:

16

Os jogos modernos de mundo aberto simplesmente não cabem na memória. Lembre-se de que a maioria dos jogos ainda é de 32 bits devido ao número de jogadores com sistemas operacionais de 32 bits, e um processo de 32 bits pode ter apenas 4 GB de memória endereçada por vez (independente da memória virtual), mas realisticamente é limitado a 2-3 GB. Atire na fragmentação e a quantidade real de objetos utilizáveis ​​que você pode ter em uma memória por vez é um pouco menor que o total de dados necessários para um ambiente grande. Mesmo em um sistema operacional de 64 bits, muitas vezes você precisa direcionar máquinas de baixa especificação com apenas 4 GB de memória para garantir a compatibilidade máxima do usuário final. Não vamos esquecer os dispositivos móveis, hardware "com pouca energia", como o WiiU, etc. Os desenvolvedores precisam visar muito mais do que grandes plataformas de PC de jogos sofisticados.

A memória virtual não é uma solução, primeiro porque não nega as limitações de espaço de endereço e também porque não é ideal. O sistema operacional pode paginar as coisas em momentos inoportunos ou inoportunos. Esse foi um problema tratado pelos sistemas operacionais quando a hibernação surgiu; a paginação dos processos para o disco e, em seguida, a paginação de volta foi significativamente mais lenta em alguns casos do que o aplicativo explicitamente transmitir o recurso de volta. Você ainda pode ver os problemas hoje quando um sistema está ficando sem memória, as páginas são paginadas para disco e o sistema não responde, torna-se essencial para executar o WM / explorer.exe. A memória virtual foi uma solução criada para um problema décadas atrás, em que os sistemas tinham muito pouca RAM e a diferença entre a velocidade da memória e do disco era muito menor. Ainda hoje' Os SSDs mais rápidos são uma fração minúscula da velocidade da RAM barata / lenta, e tentar fingir que você pode usar seu disco como RAM virtual simplesmente não é mais a melhor idéia. É uma época em que algumas pessoas fazem o oposto e carregam sistemas de arquivos em discos RAM; as restrições que levaram à criação da memória virtual não são mais verdadeiras.

Mesmo com exceção do problema no disco, o gerenciamento de recursos personalizados ainda é uma grande parte do desenvolvimento do jogo. De ganchos de depuração, preocupações com fragmentação e streaming inteligente de recursos complexos, simplesmente fingir que o mundo inteiro é uma caixa infinitamente grande de bits não é realista.

Sean Middleditch
fonte
Obrigado pela resposta detalhada. Embora ainda esteja procurando informações sobre como os drivers de GPU lidam com a memória virtual (entre a VRAM e a RAM do sistema).
jmegaffin
@ Boreal: mesmos problemas. Basta substituir "RAM" com "VRAM" e "disco" com "memória CPU
Sean Middleditch
@SeanMiddleditch +1 Boa resposta: "Esta é uma época em que algumas pessoas fazem o oposto e carregam sistemas de arquivos em discos RAM" você quer dizer arquivos mapeados na memória? Também entendo pela sua resposta que o alocador de memória personalizado impede que o sistema operacional pagine a memória, não é esse o caso, pois a memória será paginada na medida em que você solicitar a memória do kernel usando brk (), por exemplo, como paginação no PC é exatamente impedida usando um alocador de memória personalizado?
precisa
1
@ concept3d: não mapeamento de memória, mas discos de RAM literais. Você pode criar uma unidade que é apoiada pela memória e não pelo disco. O gerenciador de memória personalizado não impede a paginação (algum outro aplicativo pode estar usando toda a memória). Gerenciar recursos de forma inteligente (na camada de gerenciamento de objetos / recursos) significa simplesmente que você libera memória para objetos de que não precisa mais. Pense em caches de disco do OS mantém na memória
Sean Middleditch
6

Para um jogo de 32 bits, como a maioria dos jogos é por várias razões, mesmo um jogo que vem em um DVD de um lado (4,3 GB) já possui muito mais conteúdo que pode ser ajustado em um espaço de endereço de 32 bits. E isso assumindo que o conteúdo não está compactado no disco e, de maneira ideal, carregue tudo de uma vez na abordagem de espaço de endereço contíguo. Muitos jogos agora vêm em vários DVDs, ultrapassando facilmente 10 GB de conteúdo. Na minha experiência no PC, quando o espaço de endereço se aproximar, as alocações de 2 GB começarão a falhar e isso se tornará um limite rígido, independentemente da quantidade de memória física que o usuário tiver.

Se você pular para 64 bits, supondo que seu mecanismo o suporte, esse limite rígido desaparece, apenas para ser substituído por um limite flexível efetivo - assim que a troca de memória virtual começar, o desempenho do jogo diminuirá. inaceitavelmente. Se o processo principal precisar aguardar a volta da memória da página, a taxa de quadros gaguejará. A memória virtual pode torná-lo transparente, mas não o apresenta desempenho. Fisicamente, leva tempo para recuperar essa memória do disco e, enquanto você espera, o jogo está parado. Embora seja possível contornar (com a pré-busca em segundo plano de páginas de memória que você sabe que precisará em breve), é um processo difícil e não confiável e ainda terá implicações no desempenho.

Os algoritmos do sistema operacional para decidir quais páginas serão trocadas para o disco não têm conhecimento do seu jogo e do que provavelmente precisará a seguir. Além disso, o sistema operacional ainda precisa suportar outros aplicativos em execução simultaneamente com o seu jogo, bem como o próprio sistema operacional. Ter que parar enquanto as páginas são retornadas do disco é um enorme impacto no desempenho, e não importa se é o seu jogo, outro aplicativo ou o sistema operacional que o incorre, o desempenho do jogo sofrerá massivamente.

Portanto, independentemente de o limite de memória ser suave ou rígido, a memória ainda é limitada. Mas mesmo se você pudesse carregar tudo de uma só vez, sem atingir um limite de desempenho, ainda existem razões pelas quais você não gostaria de:

  1. Seu jogo leva muito mais tempo para carregar e chegar a um estado interativo do que o necessário, porque simplesmente carrega tudo no início e o mantém residente. Você pode carregar cerca de 150 MB / s em um disco rígido e até a unidade de DVD mais rápida (24x) é carregada em 33 MB / s. Isso significa que o conteúdo do DVD de 4,3 GB de exemplo levará pelo menos 30 segundos para carregar do HDD e mais de 133 segundos para carregar do DVD. Esses são tempos de carregamento inaceitavelmente longos.

  2. Seu jogo ocupa muito mais memória do que o justificado. Se apenas 10% do conteúdo estiver visível a qualquer momento, manter o restante residente é simplesmente um desperdício e impede o usuário de usar essa memória para outra coisa. Os usuários geralmente não perdoam os jogos que exigem uma quantidade desproporcionalmente grande de memória para funcionar corretamente.

A transmissão dinâmica de ativos do disco dinamicamente, seja em segundo plano ou de forma síncrona durante uma tela de carregamento, permite que você seja muito mais eficiente no uso da memória, com esforço desprezível e apenas uma pequena desvantagem para o usuário. Mas é uma otimização e, como qualquer outra otimização, apresenta retornos decrescentes quanto mais você tenta aplicá-la. Em algum momento, o aumento na área de cobertura da memória para manter algo residente é compensado pelas vantagens obtidas por tê-la lá sem a necessidade de carregar. Mas até que esse ponto seja alcançado, é melhor carregar apenas o que você precisa, quando precisar.

MrCranky
fonte
1

Apenas falando de maneira geral e simplista, e sem considerar os detalhes das implementações de memória virtual, o desenvolvedor sempre tem conhecimento antecipado de que a implementação da VM não possui.

O desenvolvedor sempre pode dizer: "Não preciso carregar esse arquivo de áudio no momento. A música dentro é usada apenas para o game over screen". E imediatamente após o game over screen, o desenvolvedor pode dizer: "Não preciso mais deste clipe de áudio na memória física. Ele é usado apenas para esse game over screen".

O sistema operacional não tem essa previsão. Talvez seja possível descobrir, muitas falhas de página posteriormente, que alguns clipes de áudio não são mais necessários na memória física, pois não são acessados ​​há um bom tempo. Mas transformar a previsão em retrospectiva se traduz em muitas falhas de página, e muitas falhas de página se traduzem em soluços nas taxas de quadros em um software tão crítico quanto o tempo em um videogame. Lá, a visão do desenvolvedor realmente ajuda se você deseja evitar esses soluços.

E isso se aplica conceitualmente, independentemente do hardware e software. Supondo que a paginação na memória seja cara, a previsão do desenvolvedor sempre ajudará a reduzir essa despesa.

Falando de maneira ainda mais ampla, há um ciclo interminável entre designer de hardware, designer de compilador, designer de SO / driver e desenvolvedor de aplicativos. Os desenvolvedores de hardware / compilador / SO / driver geralmente tentam implementar otimizações para acelerar seu aplicativo médio com base em seus padrões usuais de acesso à memória e, talvez, às vezes com a esperança de: "As pessoas devem ser capazes de escrever o código da maneira que quiserem e deve ser rápido ".Mas, se havia algum pensamento desse tipo, geralmente falha em campos críticos para o desempenho, porque os desenvolvedores críticos começam a aprender os detalhes complexos de seu compilador, hardware, sistema operacional, drivers, etc. e começam a escrever o código especificamente projetado para explorar o máximo possível a gravação do código mais rápido possível (como pré-buscas, divisão de campos quentes / frios, SoAs etc. para códigos compatíveis com o cache). E isso é como um jogo que nunca acaba. Essas coisas nunca são tratadas como caixas pretas em campos críticos de desempenho, pois os desenvolvedores estão competindo por desempenho.

Pessoalmente, eu meio que gostaria que a memória virtual não existisse, uma vez que adiciona uma camada adicional de imprevisibilidade de desempenho de maneiras que tendem a ser muito extremas e incorrem, muito mais uma penalidade de desempenho quando as coisas vão realmente para o sul a ponto de serem inutilizadas. Às vezes, encontro casos em que usei algum aplicativo em que digitei um ou dois dígitos extras acidentalmente quando bêbado em algum campo de entrada, o que causou o esgotamento da memória física tão rapidamente, de maneira a levar o sistema operacional a um rastreamento onde eu não conseguia ' nem clique mais no botão Cancelar na barra de progresso e tive que esperar 10 minutos enquanto pressionava Ctrl + Alt + Del para interromper um processo e xingar a mim mesmo enquanto derramava minha bebida para voltar a um ponto em que as coisas são utilizáveis ​​novamente e que apesar do arquivo de paginação ser armazenado em um SSD. Nesses casos, eu preferiria um erro de "falta de memória" ou algo assim; nesse ponto, talvez eu feche algumas das minhas 17 guias pornô (tudo bem, eu marquei meus favoritos de qualquer maneira) para liberar alguma memória e, em seguida, começar imediatamente retomando meus negócios.


fonte