No sistema Android, o limite de memória para o Memory Limiter (Android 17 e mais recentes) e o valor de referência para a métrica de memória no Google Play Console é 'RSS anônimo + espaço de troca'. Esse valor representa o nível de pressão de memória física realmente ocupado pelo processo e é uma métrica essencial que precisa ser monitorada para uma operação estável do app.
No momento, é difícil medir o uso da memória que corresponda exatamente a "RSS anônimo + espaço de troca" no tempo de execução ou estaticamente no Unity Engine.
Para resolver esse problema, esta página apresenta como rastrear o valor de 'RSS anônimo + espaço de troca' com alta confiabilidade por aproximação usando o Unity Profiler, a API ProfileRecorder e o Unity Memory Profiler em um ambiente do Unity Engine.
Verificar o uso da memória no tempo de execução
No Unity, medir diretamente o uso de memória exato de 'RSS anônimo + espaço de troca' do Android no tempo de execução sem sobrecarga pode ser desafiador. No entanto, é possível estimar esse valor (com uma variação de aproximadamente 10%) usando as APIs do Profiler integradas do Unity.
Método 1: usar o Profiler
Você pode estimar o uso da memória total somando os valores retornados pelas seguintes APIs do Profiler:
using UnityEngine;
using UnityEngine.Profiling;
public class MemoryMonitor : MonoBehaviour
{
public long GetEstimatedMemoryUsageBytes()
{
long totalReserved = Profiler.GetTotalReservedMemoryLong();
long monoHeapSize = Profiler.GetMonoHeapSizeLong();
return totalReserved + monoHeapSize;
}
}
Método 2: usar a classe ProfilerRecorder
Você pode rastrear as métricas Total Reserved Memory e Gfx Reserved Memory usando o ProfilerRecorder:
Em builds de desenvolvimento: calcule 'Total Reserved Memory' - 'Gfx Reserved Memory'.
Em builds de lançamento: use 'Total Reserved Memory' diretamente.
using Unity.Profiling;
using UnityEngine;
public class MemoryMonitor : MonoBehaviour
{
ProfilerRecorder totalRecorder;
#if DEVELOPMENT_BUILD
ProfilerRecorder gfxRecorder;
#endif
private void OnEnable()
{
totalRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Total Reserved Memory");
#if DEVELOPMENT_BUILD
gfxRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Gfx Reserved Memory");
#endif
}
private void OnDisable()
{
totalRecorder.Dispose();
#if DEVELOPMENT_BUILD
gfxRecorder.Dispose();
#endif
}
public long GetEstimatedMemoryUsageBytes()
{
#if DEVELOPMENT_BUILD
if (totalRecorder.Valid && gfxRecorder.Valid)
{
return totalRecorder.LastValue - gfxRecorder.LastValue;
}
#else
if (totalRecorder.Valid)
{
return totalRecorder.LastValue;
}
#endif
return 0;
}
}
Limitação:
As alocações de memória que ignoram o gerenciador de memória do Unity (por exemplo, NativeMalloc(IntPtr size)) não podem ser rastreadas por essas APIs.
Essas APIs podem não ser compatíveis, dependendo da versão do Unity.
Analisar a distribuição de memória (análise estática)
Se um uso da memória elevado for detectado no tempo de execução, você precisará identificar onde a memória está sendo consumida. A análise da distribuição de memória permite eliminar alocações desnecessárias e reduzir a ocupação geral de memória do jogo.
Unity Memory Profiler
Para realizar uma análise detalhada da memória e otimizar seu jogo, use o pacote Unity Memory Profiler. Para localizar os itens correspondentes ao uso de 'RSS anônimo + espaço de troca' do SO Android:
- Capture um snapshot usando o Unity Memory Profiler.
- Abra o snapshot e navegue até All of Memory > Resident Memory on Device.
Calcule a soma dos seguintes itens:
- Untracked
- Android Runtime
- Nativo
- Gerenciado
Figura 1. As descrições de memória são armazenadas na memória residente
A soma total serve como um substituto prático para o 'RSS anônimo + espaço de troca' do SO Android, oferecendo insights acionáveis para a análise de memória do jogo.
Limitação:
Em caso de pressão de memória intensa, o SO Android pode compactar ou trocar páginas de memória ativas para liberar RAM. Como o Unity Memory Profiler não pode rastrear a memória trocada, podem surgir discrepâncias durante cenários de uso da memória elevado.
Esses recursos podem ser limitados, dependendo da versão do Unity.
Exemplo de scripts em C#
Consulte os AndroidAndroidProcessStats.cs e
GameMemoryMonitor.cs scripts para exemplos de como monitorar o estado e
as ocupações de memória dos processos do jogo no tempo de execução.
- O script
AndroidProcessStatsdemonstra como usar a JNI (Java Native Interface) para vincular às APIsActivityManagerdo Android e fornece funcionalidade para buscar processos em execução, a importância deles e o estado no nível do SO. Ele também contém métodos leves para ler estatísticas de memória diretamente do sistema de arquivos/procdo Linux. - O script
GameMemoryMonitormostra como conectar essas informações para monitoramento e depuração contínuos, incluindo como consultar as APIs do Android em uma linha de execução em segundo plano para evitar sobrecarga de desempenho (já que o uso da JNI e a consulta de informações de memória podem ser caros) e como se conectar a eventos de ciclo de vida, comoOnApplicationPause, para rastrear mudanças de memória quando o app é colocado em segundo plano ou retomado.
Para usar essas ferramentas, adicione os dois scripts à pasta "Assets" e anexe o script GameMemoryMonitor a um GameObject na cena.
Avaliação mais precisa
Para verificar os valores exatos de 'RSS anônimo + espaço de troca' do SO Android, use Perfetto. Ele permite medir o uso da memória preciso no nível do sistema e analisar detalhadamente o consumo de memória do jogo.