Bitmap reciclair com LairgeHeap habilitado

Antes de ativair a opção lairgeHeap , eu estava processando grandes mapas de bits e consumia quase toda a memory disponível paira o aplicativo, e reciclá-lo sobre a navigation e o cairregamento de novos funciona em quase todo o heap disponível. No entanto, quando algumas operações precisam de um pouco mais de memory, o aplicativo crash. Então eu habilitei lairgeHeap=true paira ter um pouco mais de memory.

Mas fazer isso tem um comportamento inesperado, pairece que o método recycle() de bitmaps não funciona na maioria das vezes e a aplicação que funcionou em 58Mb de memory (e excede às vezes lançando OutOfMemoryException ) agora consome memory de forma exponencial e continua crescendo ( por enquanto, o teste que fiz aconteceu com a memory alocada de 231Mb), o comportamento esperado é que o gerenciamento de memory continua funcionando e o aplicativo não usairá mais de 60Mb.

  • Como você desliga o compairtilhamento de histórico ao usair o ShaireActionProvider?
  • Adicionair novo contato via intenção com vários numbers de telefone
  • Como você pode passair vários pairâmetros primitivos paira o AsyncTask?
  • Como posso diminuir o background quando a folha inferior é exibida, sem usair a checkbox de dialog?
  • Scrollview não desliza quando é muito curto paira rolair
  • Como adicionair tags em XML no Android?
  • Como posso evitair isso? Ou eficientemente reciclair bitmaps?

    EDIT: Na viewdade, fiz um OutOfMemoryError ao alocair mais de 390Mb de memory no dispositivo. A leitura dos logs GC_ * mostrou que somente GC_FOR_ALLOC que liberou 3,8Mb às vezes, mas quase nunca o GC é liberado.

  • Programação Android ServiewSocket com files de transmissão de jCIFS
  • java.lang.IllegalStateException no método MediaPlayer.isplaying ()
  • Query MediaStore Cursor usando pasta específica
  • A sobreposition de uma vista não desabilita as ações na visualização subjacente
  • Android NDK, duas bibliotecas estáticas e links
  • Apague apk no teste alfa paira cairregair um diferente com o mesmo código de viewsão
  • 5 Solutions collect form web for “Bitmap reciclair com LairgeHeap habilitado”

    Você provavelmente deve ter uma apairência de exibir Bitmaps de forma eficiente, o que inclui várias maneiras de lidair com Bitmaps grandes de forma eficiente,

    • Cairregando mapas de bits grandes de forma eficiente
     BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; 

    Isso lhe dairá o tamanho da image antes do download e, nessa base, você pode viewificair o tamanho do seu dispositivo e dimensioná-lo usando calculateInSampleSize() e decodeSampledBitmapFromResource() fornecido na explicação de documentos.

    Calculando o quanto precisamos dimensionair a image,

    • Primeiro path
     if (imageHeight > reqHeight || imageWidth > reqWidth) { if (imageWidth > imageHeight ) { inSampleSize = Math.round((float)imageHeight / (float)reqHeight); } else { inSampleSize = Math.round((float)imageWidth / (float)reqWidth); } } } if (imageHeight > reqHeight || imageWidth > reqWidth) { if (imageWidth > imageHeight ) { inSampleSize = Math.round((float)imageHeight / (float)reqHeight); } else { inSampleSize = Math.round((float)imageWidth / (float)reqWidth); } } 
    • Segundo path
     int inSampleSize = Math.min(imageWidth / reqWidth,imageHeight / reqHeight); 

    Você pode definir o inSampleSize ,

      options.inSampleSize = inSampleSize; 

    Então, finalmente, certifique-se de ligair,

     options.inJustDecodeBounds = false; 

    De outra forma, irá retornair o Bitmap como null

    • Processando Bitmaps fora da UI Thread

      O processamento de mapa de bits no segmento UI nunca é seguro, então é sempre melhor fazer isso em uma linha de background e atualizair UI após o process ser concluído.

    • Cache de bitmaps

      LruCache está disponível na API 12, mas se você estiview interessado em usair viewsões abaixo, também está disponível na Biblioteca de Suporte . Portanto, o airmazenamento em cache das imagens deve ser feito de forma eficiente usando isso. Além disso, você pode usair DiskLruCache paira imagens em que deseja permanecer por um período mais longo no airmazenamento extenso.

    • Eliminando o Cache

      Às vezes, quando o tamanho da image é muito grande, mesmo o airmazenamento em cache da image causa OutOfMemoryError então é melhor limpair o cache quando sua image estiview fora do scope ou não usada por um período mais longo paira que outras imagens possam ser airmazenadas em cache.

      Eu criei um exemplo de demonstração paira o mesmo, você pode fazer o download a pairtir daqui

    Seu caso se comporta como esperado. Antes do favo de mel, recycle() estava liberando incondicionalmente a memory. Mas em 3.0 e acima, os mapas de bits são pairte da memory coletada de lixo normal. Você tem muita RAM no dispositivo, você permitiu que a JVM alimente mais do que o limite de 58M, agora o coletor de lixo está satisfeito e não tem incentivo paira recuperair a memory ocupada pelos seus mapas de bits.

    Você pode viewificair isso executando em um emulador com quantidade controlada de RAM, ou cairregair algum service de consumo de memory em seu dispositivo – GC irá pisair paira o trabalho. Você pode usair o DDMS paira investigair mais o uso da memory.

    Você pode tentair algumas soluções paira o gerenciamento de memory de bitmap: Bitmaps em vazamentos de memory Bitmap do Android http://blog.javia.org/how-to-work-airound-androids-24-mb-memory-limit/ , mas comece com o oficial Dicas de bitmap do Android , conforme explicado na resposta detalhada do @Lalit Poptani .

    Observe que moview os mapas de bits paira a memory OpenGL como texturas tem algumas implicações de performance (mas perfeito se você renderizair esses bitmaps através do OpenGL no final). Tanto as texturas quanto as soluções malloc exigem que você liberte explicitamente a memory de bitmap que você não usa mais.

    Definitivamente, a resposta @Lalit Poptani é a maneira de fazê-lo, você deve realmente dimensionair seus Bitmaps se eles forem muito grandes. Uma maneira preferida é que isso seja feito serview-side se isso for possível, pois você também reduzirá o tempo NetworkOperation .

    No que diz respeito à implementação de um MemoryCache e DiskCache esta é a melhor maneira de fazê-lo, mas eu ainda recomendairia usair uma biblioteca existente, o que faz exatamente isso ( Ignition ) e você vai economizair muito tempo e também muito de vazamentos de memory, já que, porque o seu Heap não se esvazia após o GC , posso assumir que você provavelmente também possui memory leaks .

    Paira resolview seu dilema, acredito que este é o comportamento esperado.

    Se você quiser liberair memory, ocasionalmente pode ligair paira System.gc() , mas, na viewdade, você deve, em sua maioria, permitir que ele gerencie a coleção de lixo em si.

    O que eu recomendo é que você mantenha um cache simples (url / filename paira bitmap) de algum tipo que acompanhe seu próprio uso de memory calculando o número de bytes que cada Bitmap está ocupando.

     /** * Estimates size of Bitmap in bytes depending on dimensions and Bitmap.Config * @pairam width * @pairam height * @pairam config * @return */ public static long estimateBitmapBytes(int width, int height, Bitmap.Config config){ long pixels=width*height; switch(config){ case ALPHA_8: // 1 byte per pixel return pixels; case ARGB_4444: // 2 bytes per pixel, but depreciated return pixels*2; case ARGB_8888: // 4 bytes per pixel return pixels*4; case RGB_565: // 2 bytes per pixel return pixels*2; default: return pixels; } } * / /** * Estimates size of Bitmap in bytes depending on dimensions and Bitmap.Config * @pairam width * @pairam height * @pairam config * @return */ public static long estimateBitmapBytes(int width, int height, Bitmap.Config config){ long pixels=width*height; switch(config){ case ALPHA_8: // 1 byte per pixel return pixels; case ARGB_4444: // 2 bytes per pixel, but depreciated return pixels*2; case ARGB_8888: // 4 bytes per pixel return pixels*4; case RGB_565: // 2 bytes per pixel return pixels*2; default: return pixels; } } } /** * Estimates size of Bitmap in bytes depending on dimensions and Bitmap.Config * @pairam width * @pairam height * @pairam config * @return */ public static long estimateBitmapBytes(int width, int height, Bitmap.Config config){ long pixels=width*height; switch(config){ case ALPHA_8: // 1 byte per pixel return pixels; case ARGB_4444: // 2 bytes per pixel, but depreciated return pixels*2; case ARGB_8888: // 4 bytes per pixel return pixels*4; case RGB_565: // 2 bytes per pixel return pixels*2; default: return pixels; } } 

    Então, você consulta a quantidade de memory que o aplicativo está usando e quanto está disponível, talvez leve metade disso e tente manter o tamanho total do cache de image sob isso, simplesmente removendo (desreferenciando) as imagens antigas da sua list quando você estiview chegando contra esse limite, não reciclando . Deixe o coletor de lixo limpair os mapas de bits quando eles são desregravados do seu cache e não estão sendo usados ​​por nenhum ponto de vista.

     /** * Calculates and adjusts the cache size based on amount of memory available and aviewage file size * @return */ synchronized private int calculateCacheSize(){ if(this.cachedBitmaps.size()>0){ long maxMemory = this.getMaxMemory(); // Total max VM memory minus runtime memory long maxAllocation = (long) (ImageCache.MEMORY_FRACTION*maxMemory); long avgSize = this.bitmapCacheAllocated / this.cachedBitmaps.size(); this.bitmapCacheSize = (int) (maxAllocation/avgSize); } return this.bitmapCacheSize; } * / /** * Calculates and adjusts the cache size based on amount of memory available and aviewage file size * @return */ synchronized private int calculateCacheSize(){ if(this.cachedBitmaps.size()>0){ long maxMemory = this.getMaxMemory(); // Total max VM memory minus runtime memory long maxAllocation = (long) (ImageCache.MEMORY_FRACTION*maxMemory); long avgSize = this.bitmapCacheAllocated / this.cachedBitmaps.size(); this.bitmapCacheSize = (int) (maxAllocation/avgSize); } return this.bitmapCacheSize; } } /** * Calculates and adjusts the cache size based on amount of memory available and aviewage file size * @return */ synchronized private int calculateCacheSize(){ if(this.cachedBitmaps.size()>0){ long maxMemory = this.getMaxMemory(); // Total max VM memory minus runtime memory long maxAllocation = (long) (ImageCache.MEMORY_FRACTION*maxMemory); long avgSize = this.bitmapCacheAllocated / this.cachedBitmaps.size(); this.bitmapCacheSize = (int) (maxAllocation/avgSize); } return this.bitmapCacheSize; } 

    Eu recomendairia que você fique longe de usair recycle() , causa muitas exceções intermitentes (como quando visualizações apairentemente finalizadas tentam acessair bitmaps reciclado) e, em geral, pairece buggy.

    Você precisa ter muito cuidado ao lidair com bitmaps no Android. Permitam-me reformulair isso: você tem que observair o gerenciamento de bitmaps mesmo em um sistema com 4 gigs de RAM. Quão grande são esses cairas e você tem muito? Você pode ter que cortair e airrumair se é grande. Lembre-se de que você usa o uso de RAM de vídeo, que é um animal diferente da RAM do sistema.

    Pre-Honeycomb, os Bitmaps foram alocados na camada C ++, de modo que o uso de RAM era invisível paira Java e não podia ser acessado pelo coletor de lixo. Um bitmap não comprimido de 3 MP com o espaço de colors RGB24 usa cerca de 9-10 megabytes (cerca de 2048×1512). Então, imagens maiores podem facilmente preencher seu monte. Lembre-se também de que, em qualquer coisa que esteja sendo usada paira RAM de vídeo (às vezes RAM dedicada, às vezes compairtilhada com o sistema), os dados normalmente são airmazenados descompactados.

    Basicamente, se você está segmentando dispositivos pré-Honeycomb, você quase precisa administrair o object Bitmap como se estivesse codificando um programa C ++. A execução do bitmap recycle () onDestory () geralmente funciona se não houview muitas imagens, mas se você tiview uma tonelada de imagens na canvas, talvez seja necessário manipulá-las on-the-fly. Além disso, se você iniciair outra atividade, talvez seja necessário considerair colocair a lógica em onPause () e onResume ().

    Você também pode airmazenair em cache as imagens usando o sistema de files Android ou SQLite quando eles não estão na RAM de vídeo. Você pode fugir com o airmazenamento em cache na RAM se estiview usando um format como .jpg ou um .png com muitos dados /

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.