Android: como funciona a reciclagem de bitmap ()?


88

Digamos que carreguei uma imagem em um objeto bitmap como

Bitmap myBitmap = BitmapFactory.decodeFile(myFile);

Agora, o que acontecerá se eu carregar outro bitmap como

myBitmap = BitmapFactory.decodeFile(myFile2);

O que acontece com o primeiro myBitmap? Ele é coletado como lixo ou preciso coletá-lo manualmente antes de carregar outro bitmap, por exemplo. myBitmap.recycle()?

Além disso, existe uma maneira melhor de carregar imagens grandes e exibi-las uma após a outra enquanto faz a reciclagem pelo caminho?

Respostas:



22

Acho que o problema é o seguinte: nas versões pré-Honeycomb do Android, os dados reais de bitmap não são armazenados na memória da VM, mas sim na memória nativa. Esta memória nativa é liberada quando o Bitmapobjeto java correspondente é GC'd.

No entanto , quando você fica sem memória nativa, o dalvik GC não é acionado, então é possível que seu aplicativo use muito pouco da memória java, então o dalvik GC nunca é invocado, mas usa toneladas de memória nativa para bitmaps que eventualmente causa um erro OOM.

Pelo menos é o meu palpite. Felizmente, no Honeycomb e em versões posteriores, todos os dados de bitmap são armazenados na VM, portanto, você não deve precisar usá-los recycle(). Mas para os milhões de 2,3 usuários (a fragmentação balança o punho ), você deve usar recycle()sempre que possível (um grande aborrecimento). Ou, alternativamente, você pode invocar o GC.


21

Você precisará chamar myBitmap.recycle () antes de carregar a próxima imagem.

Dependendo da fonte do seu myFile (por exemplo, se for algo que você não tem controle sobre o tamanho original), ao carregar uma imagem em vez de simplesmente reamostrar algum número arbitrário, você deve dimensionar a imagem para o tamanho de exibição.

if (myBitmap != null) {
    myBitmap.recycle();
    myBitmap = null;
}
Bitmap original = BitmapFactory.decodeFile(myFile);
myBitmap = Bitmap.createScaledBitmap(original, displayWidth, displayHeight, true);
if (original != myBitmap)
    original.recycle();
original = null;

Eu armazeno em cache displayWidth & displayHeight em uma estática que inicializei no início da minha atividade.

Display display = getWindowManager().getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();

3
Você não precisa chamar recycle (), é apenas uma boa ideia se você quiser liberar a memória imediatamente.
Karu

13
A resposta aceita diz "Se você deseja liberar memória o mais rápido possível, deve chamar recycle ()". Sua resposta diz "Você precisará chamar myBitmap.recycle ()". Há uma diferença entre "deveria" e "preciso", e o último está incorreto neste caso.
Karu

1
O contexto é importante. A pergunta era "Também existe uma maneira melhor de carregar imagens grandes e exibi-las uma após a outra, reciclando no caminho".
djunod

3
A partir do Android 4.1, o exemplo acima pode falhar porque createScaledBitmap pode retornar, em alguns casos, a mesma instância do original. Isso significa que você deve verificar o original! = MyBitmap antes de reciclar o original.
Jeremyfa

1
@Jeremyfa Ele só retorna a imagem original se você especificar uma largura e altura que sejam idênticas ao original. Nesse caso, o dimensionamento é discutível, portanto, é melhor salvar alguns processos pulando-o e retornando a imagem original. Não deve "quebrar" nada ...
Jabari

11

Depois que o bitmap foi carregado na memória, na verdade ele foi feito por dados de duas partes. A primeira parte inclui algumas informações sobre o bitmap, a outra parte inclui informações sobre os pixels do bitmap (é composto por uma matriz de bytes). A primeira parte existe na memória usada Java, a segunda parte existe na memória usada C ++. Eles podem usar a memória um do outro diretamente. Bitmap.recycle () é usado para liberar a memória de C ++. Se você apenas fizer isso, o GC irá coletar a parte de java e a memória de C será sempre usada.


1 para uma maneira interessante, mas muito boa de descrever porque a memória não está disponível para GC imediato - uma boa maneira.
Richard Le Mesurier

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.