Analisando a pegada de memória física do seu aplicativo usando o Memory Profiler

ANTON KRUGLYAKOV / UNITYSenior Software Engineer
Mar 28, 2023|10 Min
Analisando a pegada de memória física do seu aplicativo usando o Memory Profiler
Esta página da Web foi automaticamente traduzida para sua conveniência. Não podemos garantir a precisão ou a confiabilidade do conteúdo traduzido. Se tiver dúvidas sobre a precisão do conteúdo traduzido, consulte a versão oficial em inglês da página da Web.

Quando se trata de detectar problemas de memória com eficiência e otimizar o desempenho, as informações mostradas no Memory Profiler, bem como a precisão das informações, são essenciais. Estamos investindo esforços significativos nessa área. Em dois blogs recentes, membros da minha equipe apresentaram o Memory Profiler 1.0.0 e compartilharam cinco fluxos de trabalho principais para diagnosticar e examinar problemas relacionados à memória no seu jogo.

Em breve, lançaremos o Memory Profiler 1.1 (uma versão experimental já está disponível), que inclui rótulos e descrições atualizados para explicar como a memória funciona e como a pegada de memória do aplicativo é calculada.

Como a pegada de memória continua sendo um tópico importante em nossas conversas com desenvolvedores, estou aqui para responder às suas perguntas frequentes – especificamente, para cobrir estes três tópicos:

  • O que é memória residente
  • Como a pegada de memória do aplicativo é calculada
  • Como analisar a pegada de memória
Memória residente, definida

Vamos nos aprofundar na alocação de memória no Unity. Quando o mecanismo aloca memória, ele primeiro reserva várias páginas de memória no espaço de endereço virtual que podem se adequar à alocação solicitada. Páginas são as menores unidades de gerenciamento de memória. O espaço de endereço virtual e o armazenamento físico são organizados em páginas, e o tamanho da página depende da plataforma usada. Por exemplo, em computadores x86 o tamanho de uma página é de 4 KB.

Depois que o mecanismo reserva páginas suficientes, ele solicita ao sistema operacional (SO) que “confirme” o armazenamento físico na memória. É por isso que a memória alocada é frequentemente chamada de “comprometida”. Em seguida, o sistema operacional registra que as páginas agora têm armazenamento físico atribuído e podem ser acessadas. A “memória total comprometida” relatada pelo seu aplicativo aumentará. No entanto, o espaço de memória física do seu aplicativo permanece o mesmo.

Representação gráfica de páginas reservadas | Mergulho profundo no Memory Profiler

A pegada permanece a mesma porque, mesmo que você tenha comprometido sua região com armazenamento físico, a maioria dos sistemas operacionais são preguiçosos e econômicos, então não há atribuição de um local de armazenamento físico específico. Por exemplo, digamos que você decida escrever algo na região comprometida. Ainda não há nenhuma memória física abaixo da região, então acessá-la causará uma falha de página. Em resposta, o gerenciador de memória do sistema operacional alocará uma página física previamente disponível para concluir sua operação. Como todas as operações são executadas com granularidade de tamanho de página, as páginas não acessadas da região permanecerão vazias e sem memória física atribuída. Da mesma forma, o tamanho da memória residente do seu aplicativo aumentará pelo tamanho total de todas as páginas de memória física alocadas para concluir sua operação.

Representação gráfica de páginas confirmadas | Mergulho profundo no Memory Profiler

Se uma página não for acessada por um tempo ou a demanda por memória física for alta, um sistema operacional pode descarregar algumas páginas da sua região alocada para a memória compactada ou para um arquivo de troca de páginas, dependendo do que for suportado na sua plataforma.

Representação gráfica de páginas trocadas | Mergulho profundo no Memory Profiler

Nesse caso, a memória alocada relatada pelo seu aplicativo permanecerá a mesma, mas o tamanho da memória residente diminuirá.

Como a pegada de memória do aplicativo é calculada

Como você já deve ter percebido, se você observar apenas a memória alocada, poderá ser enganado sobre qual alocação consome sua memória física, o que pode induzi-lo a otimizar algo que não é um problema. Isso não só desperdiça seu tempo valioso como você não vê nenhuma diferença no desempenho e na estabilidade do seu aplicativo.

No geral, o estado da memória do seu aplicativo pode ser descrito por este diagrama:

Diagrama do estado da memória do aplicativo

Em resumo, veja como a pegada de memória é calculada:

Pegada de memória física = Memória residente do aplicativo + Páginas de memória compactadas do aplicativo
Analisar a pegada de memória

No Memory Profiler 1.1, as visualizações Resumo, Objetos Unitye Toda a Memória não apenas mostrarão o tamanho da memória alocada , mas também fornecerão informações sobre a memória residente. No entanto, essas informações só serão mostradas se o snapshot do Memory Profiler for feito com o Unity 2023.1 ou mais recente. Com snapshots mais antigos, você ainda verá a interface do usuário atualizada e visualizações detalhadas, mas sem informações sobre a memória residente.

Visão resumida do Memory Profiler 1.1 no Unity Editor

A visualização Resumo fornece uma visão geral e uma métrica essencial: Residente total no dispositivo. Se seu aplicativo precisa ser executado em uma plataforma com memória limitada, o Total Resident on Device é essencial para revisar avisos de pouca memória e remoções por falta de memória. Como regra geral, você não deve usar mais de 70% da memória física total disponível em um dispositivo.

Para uma análise detalhada, você pode usar as visualizações Unity Objects e All of Memory. Você precisará selecionar Residente no dispositivo ou Alocado e residente no dispositivo no menu suspenso e classificar por tamanho do residente para ver os objetos que mais contribuem para a memória física total usada.

Exibição de toda a memória para o Memory Profiler 1.1 no Unity Editor

Ao analisar o uso da memória residente, lembre-se:

  • A memória gerenciada será predominantemente residente. O Mono Heap e o Boehm Garbage Collector acessam objetos regularmente e os tornam residentes.
  • A memória gráfica (estimada) é mostrada como estimada. Na maioria das plataformas, não temos acesso a informações sobre a localização exata dos recursos gráficos, então estimamos o tamanho com base nas informações disponíveis, como largura, altura, profundidade, formato de pixel e assim por diante. Isso também significa que não temos informações sobre o status de residência dos recursos gráficos. Por razões de usabilidade, todos os objetos gráficos são mostrados apenas no modo de visualização Alocado.
  • Não rastreada é toda a memória relatada pelo sistema operacional como alocada pelo aplicativo, mas que carece de informações sólidas sobre a origem da alocação. Podem ser plugins nativos, bibliotecas do sistema operacional, pilhas de threads, etc. Em algumas plataformas, fornecemos insights adicionais sobre quem pode ter alocado essa memória na divisão do grupo.

Ao analisar a memórianativa , que contém todas as alocações não gerenciadas do Unity usadas por objetos, você verá o item Memória reservada . Esta é a memória alocada pelo Unity Memory Manager, mas não usada por nenhum objeto Unity durante a captura. Aqui estão algumas informações úteis:

  • A memória reservada pode ser residente, o que significa que pode ter havido um objeto que foi excluído recentemente.
  • Você pode acessar informações adicionais sobre o detalhamento da memória reservada acessando as configurações do Memory Profiler e ativando a caixa de seleção “Mostrar detalhamento da memória reservada”. Por padrão, isso está desabilitado, pois o detalhamento reservado nem sempre contém informações úteis suficientes e exige um profundo entendimento de como o Unity Memory Manager funciona.
  • Você pode aprender mais sobre o Unity Memory Manager e estratégias de alocação na documentação de configuração dos alocadores .

Em algumas plataformas, mostramos grupos adicionais específicos da plataforma se eles forem de tamanho significativo, como o Android Runtime no Android. Aqui estão algumas notas sobre o Android Runtime:

  • Em algumas versões, o Android Runtime tende a pré-alocar uma quantidade significativa de memória, mas nunca a utiliza. Nesse caso, a memória alocada não aumenta a pegada de memória do aplicativo e somente a parte residente dela precisa ser considerada.
  • Se a parte residente do Android Runtime estiver ocupando uma quantidade significativa da memória do aplicativo, use o criador de perfil do Android Studio para analisar as alocações feitas em Java.
  • Embora o Android não tenha um arquivo de paginação ou compactação de memória por padrão, o kernel do Linux permite que os aplicativos sobrecarreguem e aloquem mais memória do que a disponível fisicamente.
  • Ao capturar, certifique-se de entender o dispositivo que você está usando. Alguns fornecedores fornecem o kernel do Android Linux com compactação de memória (zRAM) ou ferramentas de arquivo de troca de página personalizadas pelo fornecedor.
Conclusão

Esperamos que esta visão geral do que esperar do Memory Profiler 1.1 (versão experimental disponível agora) e a exploração de vários tópicos sobre o consumo de memória tenham sido úteis.

Minha equipe e eu planejamos continuar aprimorando o Memory Profiler para fornecer informações mais precisas e direcionadas, além de alertá-lo sobre possíveis situações de falta de memória e quão próximas elas podem estar. Acompanhe o progresso do nosso roteiro de produtos e diga-nos o que você acha.

Compartilhe seu feedback conosco nos fóruns. Não deixe de ficar atento aos novos blogs técnicos de outros desenvolvedores do Unity como parte do processo contínuo SérieTech from the Trenches.