Há duas maneiras de pensar sobre sua frase "tamanho de heap do aplicativo disponível":
Quanto heap meu aplicativo pode usar antes que um erro grave seja acionado? E
Quanto heap meu aplicativo deve usar, dadas as restrições da versão do sistema operacional Android e o hardware do dispositivo do usuário?
Existe um método diferente para determinar cada uma das opções acima.
Para o item 1 acima: maxMemory()
que pode ser invocado (por exemplo, no onCreate()
método da sua atividade principal ) da seguinte maneira:
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));
Este método informa quantos bytes totais de heap seu aplicativo tem permissão para usar.
Para o item 2 acima: getMemoryClass()
que pode ser chamado da seguinte maneira:
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));
Esse método informa aproximadamente quantos megabytes de heap seu aplicativo deve usar se quiser respeitar adequadamente os limites do dispositivo atual e os direitos de outros aplicativos de serem executados sem serem repetidamente forçados ao ciclo onStop()
/ onResume()
, pois são rudes. fica sem memória enquanto o aplicativo elefantino toma banho no jacuzzi Android.
Essa distinção não está claramente documentada, até onde eu sei, mas testei essa hipótese em cinco dispositivos Android diferentes (veja abaixo) e confirmei, para minha satisfação, que esta é uma interpretação correta.
Para uma versão padrão do Android, maxMemory()
normalmente retornará aproximadamente o mesmo número de megabytes indicado em getMemoryClass()
(isto é, aproximadamente um milhão de vezes o último valor).
A única situação (da qual eu sei) para a qual os dois métodos podem divergir é em um dispositivo raiz executando uma versão Android como o CyanogenMod, que permite ao usuário selecionar manualmente o tamanho de heap permitido para cada aplicativo. No CM, por exemplo, esta opção aparece em "Configurações do CyanogenMod" / "Desempenho" / "Tamanho da pilha da VM".
NOTA: Esteja ciente de que a configuração manual desse valor pode prejudicar o sistema, especialmente se você selecionar um valor menor que o normal para o seu dispositivo.
Aqui estão meus resultados de teste, mostrando os valores retornados por maxMemory()
e getMemoryClass()
para quatro dispositivos diferentes executando o CyanogenMod, usando dois valores de heap diferentes (definidos manualmente) para cada um:
- G1:
- Com o tamanho de heap da VM definido como 16 MB:
- maxMemory: 16777216
- getMemoryClass: 16
- Com o tamanho de heap da VM definido como 24 MB:
- maxMemory: 25165824
- getMemoryClass: 16
- Moto Droid:
- Com o tamanho de heap da VM definido como 24 MB:
- maxMemory: 25165824
- getMemoryClass: 24
- Com o tamanho de heap da VM definido como 16 MB:
- maxMemory: 16777216
- getMemoryClass: 24
- Nexus One:
- Com o tamanho do heap da VM definido como 32 MB:
- maxMemory: 33554432
- getMemoryClass: 32
- Com o tamanho do heap da VM definido como 24 MB:
- maxMemory: 25165824
- getMemoryClass: 32
- Viewsonic GTab:
- Com o tamanho de heap da VM definido como 32:
- maxMemory: 33554432
- getMemoryClass: 32
- Com o tamanho de heap da VM definido como 64:
- maxMemory: 67108864
- getMemoryClass: 32
Além do exposto, testei em um tablet Novo7 Paladin com Ice Cream Sandwich. Essa era essencialmente uma versão de estoque do ICS, exceto que eu enraizei o tablet através de um processo simples que não substitui todo o sistema operacional e, em particular, não fornece uma interface que permita que o tamanho do heap seja ajustado manualmente.
Para esse dispositivo, aqui estão os resultados:
- Novo7
- maxMemory: 62914560
- getMemoryClass: 60
Também (por Kishore em um comentário abaixo):
- HTC One X
- maxMemory: 67108864
- getMemoryClass: 64
E (pelo comentário de akauppi):
- Samsung Galaxy Core Plus
- maxMemory: (Não especificado no comentário)
- getMemoryClass: 48
- largeMemoryClass: 128
Por um comentário de cmcromance:
- Grande pilha do Galaxy S3 (Jelly Bean)
- maxMemory: 268435456
- getMemoryClass: 64
E (comentários de tencent):
- LG Nexus 5 (4.4.3) normal
- maxMemory: 201326592
- getMemoryClass: 192
- Pilha grande de LG Nexus 5 (4.4.3)
- maxMemory: 536870912
- getMemoryClass: 192
- Galaxy Nexus (4.3) normal
- maxMemory: 100663296
- getMemoryClass: 96
- Pilha grande do Galaxy Nexus (4.3)
- maxMemory: 268435456
- getMemoryClass: 96
- Galaxy S4 Play Store (4.4.2) normal
- maxMemory: 201326592
- getMemoryClass: 192
- Grande pilha do Galaxy S4 Play Store Edition (4.4.2)
- maxMemory: 536870912
- getMemoryClass: 192
Outros dispositivos
- Huawei Nexus 6P (6.0.1) normal
- maxMemory: 201326592
- getMemoryClass: 192
Não testei esses dois métodos usando a opção especial manifest: android: largeHeap = "true" disponível desde o Honeycomb, mas, graças ao cmcromance e ao tencent, temos alguns exemplos de valores largeHeap, conforme relatado acima.
Minha expectativa (que parece ser suportada pelos números grandes do heap acima) seria que essa opção tivesse um efeito semelhante à configuração manual do heap por meio de um sistema operacional raiz - ou seja, aumentaria o valor maxMemory()
ao sair getMemoryClass()
sozinho. Há outro método, getLargeMemoryClass (), que indica quanta memória é permitida para um aplicativo usando a configuração largeHeap. A documentação para getLargeMemoryClass () afirma: "a maioria dos aplicativos não precisa dessa quantidade de memória e deve permanecer com o limite de getMemoryClass ()".
Se eu adivinhei corretamente, usar essa opção teria os mesmos benefícios (e perigos) que o espaço disponibilizado por um usuário que aumentou a pilha por meio de um sistema operacional raiz (por exemplo, se o aplicativo usar memória adicional, provavelmente não funcionará tão bem com outros aplicativos que o usuário esteja executando ao mesmo tempo).
Observe que a classe de memória aparentemente não precisa ter um múltiplo de 8 MB.
Podemos ver, acima, que o getMemoryClass()
resultado é imutável para uma determinada configuração de dispositivo / SO, enquanto o valor maxMemory () muda quando o heap é definido de forma diferente pelo usuário.
Minha própria experiência prática é que, no G1 (que tem uma classe de memória de 16), se eu selecionar manualmente 24 MB como o tamanho da pilha, posso executar sem erros, mesmo quando meu uso de memória puder subir para 20 MB (presumivelmente chegam a 24 MB, embora eu não tenha tentado isso). Mas outros aplicativos igualmente grandes podem ser lavados da memória como resultado da porcaria do meu próprio aplicativo. E, por outro lado, meu aplicativo pode ficar sem memória se esses outros aplicativos de alta manutenção forem trazidos ao primeiro plano pelo usuário.
Portanto, você não pode exceder a quantidade de memória especificada por maxMemory()
. E, você deve tentar permanecer dentro dos limites especificados por getMemoryClass()
. Uma maneira de fazer isso, se tudo mais falhar, pode ser limitar a funcionalidade desses dispositivos de maneira a economizar memória.
Por fim, se você planeja ultrapassar o número de megabytes especificado em getMemoryClass()
, meu conselho é trabalhar arduamente para salvar e restaurar o estado do aplicativo, para que a experiência do usuário seja praticamente ininterrupta se ocorrer um onStop()
/ onResume()
ciclo.
No meu caso, por motivos de desempenho, estou limitando meu aplicativo a dispositivos com a versão 2.2 e superior, e isso significa que quase todos os dispositivos que executam meu aplicativo terão uma memoryClass de 24 ou superior. Para que eu possa projetar para ocupar até 20 MB de heap e me sentir bastante confiante de que meu aplicativo funcionará bem com os outros aplicativos que o usuário possa estar executando ao mesmo tempo.
Mas sempre haverá alguns usuários enraizados que carregaram uma versão 2.2 ou superior do Android em um dispositivo mais antigo (por exemplo, um G1). Quando você encontra essa configuração, o ideal é reduzir o uso de memória, mesmo que maxMemory()
esteja lhe dizendo que você pode ir muito mais alto do que os 16 MB que getMemoryClass()
estão lhe dizendo que você deveria estar alvejando. E se você não pode garantir com segurança que a sua aplicação vai viver dentro desse orçamento, em seguida, pelo menos, fazer-se de que onStop()
/ onResume()
funciona perfeitamente.
getMemoryClass()
, como indicado por Diane Hackborn (hackbod) acima, só está disponível no nível 5 da API (Android 2.0) e, como aconselha, você pode assumir que o hardware físico de qualquer dispositivo executando uma versão anterior do sistema operacional foi projetado para oferecer suporte ideal a aplicativos que ocupam um espaço de heap não superior a 16 MB.
Por outro lado, maxMemory()
de acordo com a documentação, está disponível todo o caminho de volta ao nível API 1. maxMemory()
, em uma pré-versão 2.0, provavelmente irá retornar um valor de 16 MB, mas eu fazer ver que em meus (muito mais tarde) versões CyanogenMod do usuário pode selecionar um valor de heap tão baixo quanto 12MB, o que presumivelmente resultaria em um limite de heap mais baixo e, portanto, sugiro que você continue testando o maxMemory()
valor, mesmo para versões do sistema operacional anteriores à 2.0. Você pode até se recusar a executar no caso improvável de que esse valor seja definido ainda mais baixo que 16 MB, se você precisar ter mais do que o maxMemory()
indicado é permitido.