Pérdida de memoria a pesar de usar weakreference
En mi aplicación estoy usando un listview y un listadapter. Cuando se hace clic en un cierto subitem de la vista de lista, hay una vista de texto seleccionable que carga varios mapas de bits en una vista de desplazamiento, y esta vista de desplazamiento se muestra en un alerta.
Todo esto ocurre en una clase que extiende BaseExpandableListAdapter y cuando se hace clic en este enlace de texto – se llama a una clase interna estática responsable de cargar todos estos mapas de bits (9). Esta clase interna se extiende asynctask.
- Uso de memoria entre Android 2.2 y 2.3
- Android java, obtener más uso de memoria permitido
- Apertura de la cámara en un proceso diferente
- Razones por las que mi aplicación Android se bloquea en mi teléfono de forma consistente, pero no en mi emulador
- OutOfMemoryError al cargar actividades
Antes de cargar estos mapas de bits en la vista de desplazamiento, se llaman dos métodos estáticos de esta clase interna que reducen los bitamps a un tamaño que se ajuste a la pantalla. Aquí utilizo Bitmapfactory.decoderesource y Bitmap.scaledownBitmap.
Todo esto funciona bien, pero el programa sufre de un memoryleak. Esta filtración fue bastante grande antes porque esta clase interna no era estática. Así que la fuga se redujo haciendo esta clase interna estática. Sí – reducido, pero no eliminado.
También he hecho weakreference de varios objetos pero sin éxito. Por ejemplo – he hecho una referencia débil del objeto que se refiere a la clase interna. He hecho una débil referencia del contexto que se pasa a la clase interna. Incluso he hecho w una referencia débil de los mapas de bits. Ningún éxito en absoluto.
La pila de mi Samsung Galazy s3 es de 64 MB. Cuando el listview con todo su subitem es cargado primero el montón usado es cerca de 17 MB. Entonces, cuando se cargan 9 mapas de bits, se empuja a unos 42 MB. Si a continuación, haga clic en otro subitem con imágenes utilizadas montón es el mismo – pero después de seguir haciendo clic y cargar mapas de bits el montón de repente jumbs a 47 MB … entonces el mismo escenario …. se queda parado por un tiempo – y luego hasta 52 MB …. 56 MB. Así que tengo que hacer clic y cargar mapas de bits casi para salir de la memoria. Digamos 15 – 20 minutos de uso intensivo.
Conclusión : Hacer la clase interna de estática me ayudó a reducir la pérdida de memoria. Pero a pesar de hacer referencias débiles de varios objetos (especialmente el contexto) no he podido reducir el escape más lejos.
¿Alguna sugerencia?
El código de abajo es un poco complicado ….
static class BitmapWorkerTask extends AsyncTask <Integer, Void, Bitmap[]> { private int[] data; private int[] width, height; private int nmbrOfImages; private String[] scrollText; private ImageView mImage; private View view; private LayoutInflater factory; private AlertDialog.Builder alertadd; private Context context; private WeakReference <Context> sc; private WeakReference <ImageView> mImageV; private WeakReference <Bitmap[]> bitmapV; public BitmapWorkerTask(int[] width, int[] height, int nmbrOfImages, String[] scrollText, Context context) { this.width = width; this.height = height; this.nmbrOfImages = nmbrOfImages; this.scrollText = scrollText; this.context = context; mImage = null; view = null; factory = null; alertadd = null; System.gc(); sc = new WeakReference <Context> (context); try { for (int i = 0; i < scaledBitmap.length; i++) { scaledBitmap[i].recycle(); scaledBitmap[i] = null; } } catch (NullPointerException ne) { System.out.println("nullpointerexception ... gick inte recycla bitmapbilder"); } switch (nmbrOfImages) { case 0: data = new int[1]; break; case 1: data = new int[3]; break; case 2: data = new int[5]; break; case 3: data = new int[9]; break; } } @Override protected Bitmap[] doInBackground(Integer ... params) { switch (nmbrOfImages) { case 0: data[0] = params[0]; break; case 1: data[0] = params[0]; data[1] = params[1]; data[2] = params[2]; break; case 2: data[0] = params[0]; data[1] = params[1]; data[2] = params[2]; data[3] = params[3]; data[4] = params[4]; break; case 3: data[0] = params[0]; data[1] = params[1]; data[2] = params[2]; data[3] = params[3]; data[4] = params[4]; data[5] = params[5]; data[6] = params[6]; data[7] = params[7]; data[8] = params[8]; break; } alertadd = new AlertDialog.Builder(sc.get()); factory = LayoutInflater.from(sc.get()); Bitmap[] bm = decodeSampledBitmapFromResource(sc.get().getResources(), data, width, height); bitmapV = new WeakReference <Bitmap[]> (bm); return bitmapV.get(); } protected void onPostExecute(Bitmap[] bitmap) { switch (nmbrOfImages) { case 0: if (view == null) { view = factory.inflate(R.layout.alertviews, null); } mImage = (ImageView) view.findViewById(R.id.extra_img); mImage.setImageBitmap(bitmap[0]); alertadd.setView(view); alertadd.setNeutralButton("Here!", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dlg, int sumthin) { } }); alertadd.show(); break; case 1: if (view == null) { view = factory.inflate(R.layout.alertviews2, null); } mImage = (ImageView) view.findViewById(R.id.img1); mImage.setImageBitmap(bitmap[0]); mImage = (ImageView) view.findViewById(R.id.img2); mImage.setImageBitmap(bitmap[1]); mImage = (ImageView) view.findViewById(R.id.img3); mImage.setImageBitmap(bitmap[2]); try { TextView mText2 = (TextView) view.findViewById(R.id.text_img1_scrollview); mText2.setText(scrollText[0]); mText2 = (TextView) view.findViewById(R.id.text_img2_scrollview); mText2.setText(scrollText[1]); mText2 = (TextView) view.findViewById(R.id.text_img3_scrollview); mText2.setText(scrollText[2]); } catch (NullPointerException ne) { System.out.println("nullpointerexception ... TextView i metoden onPostExecute"); } alertadd.setView(view); alertadd.setNeutralButton("Here!", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dlg, int sumthin) { } }); alertadd.show(); break; case 2: if (view == null) { view = factory.inflate(R.layout.alertviews3, null); } mImage = (ImageView) view.findViewById(R.id.img1); mImage.setImageBitmap(bitmap[0]); mImage = (ImageView) view.findViewById(R.id.img2); mImage.setImageBitmap(bitmap[1]); mImage = (ImageView) view.findViewById(R.id.img3); mImage.setImageBitmap(bitmap[2]); mImage = (ImageView) view.findViewById(R.id.img4); mImage.setImageBitmap(bitmap[3]); mImage = (ImageView) view.findViewById(R.id.img5); mImage.setImageBitmap(bitmap[4]); try { TextView mText3 = (TextView) view.findViewById(R.id.text_img1_scrollview); mText3.setText(scrollText[0]); mText3 = (TextView) view.findViewById(R.id.text_img2_scrollview); mText3.setText(scrollText[1]); mText3 = (TextView) view.findViewById(R.id.text_img3_scrollview); mText3.setText(scrollText[2]); mText3 = (TextView) view.findViewById(R.id.text_img4_scrollview); mText3.setText(scrollText[3]); mText3 = (TextView) view.findViewById(R.id.text_img5_scrollview); mText3.setText(scrollText[4]); } catch (NullPointerException ne) { System.out.println("nullpointerexception ... TextView i metoden onPostExecute"); } alertadd.setView(view); alertadd.setNeutralButton("Here!", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dlg, int sumthin) { } }); alertadd.show(); break; case 3: if (view == null) { view = factory.inflate(R.layout.alertviews4, null); } AlertDialog.Builder alertadd = new AlertDialog.Builder(context); mImage = (ImageView) view.findViewById(R.id.img1); mImage.setImageBitmap(bitmap[0]); mImage = (ImageView) view.findViewById(R.id.img2); mImage.setImageBitmap(bitmap[1]); mImage = (ImageView) view.findViewById(R.id.img3); mImage.setImageBitmap(bitmap[2]); mImage = (ImageView) view.findViewById(R.id.img4); mImage.setImageBitmap(bitmap[3]); mImage = (ImageView) view.findViewById(R.id.img5); mImage.setImageBitmap(bitmap[4]); mImage = (ImageView) view.findViewById(R.id.img6); mImage.setImageBitmap(bitmap[5]); mImage = (ImageView) view.findViewById(R.id.img7); mImage.setImageBitmap(bitmap[6]); mImage = (ImageView) view.findViewById(R.id.img8); mImage.setImageBitmap(bitmap[7]); mImage = (ImageView) view.findViewById(R.id.img9); mImage.setImageBitmap(bitmap[8]); try { TextView mText4 = (TextView) view.findViewById(R.id.text_img1_scrollview); mText4.setText(scrollText[0]); mText4 = (TextView) view.findViewById(R.id.text_img2_scrollview); mText4.setText(scrollText[1]); mText4 = (TextView) view.findViewById(R.id.text_img3_scrollview); mText4.setText(scrollText[2]); mText4 = (TextView) view.findViewById(R.id.text_img4_scrollview); mText4.setText(scrollText[3]); mText4 = (TextView) view.findViewById(R.id.text_img5_scrollview); mText4.setText(scrollText[4]); mText4 = (TextView) view.findViewById(R.id.text_img6_scrollview); mText4.setText(scrollText[5]); mText4 = (TextView) view.findViewById(R.id.text_img7_scrollview); mText4.setText(scrollText[6]); mText4 = (TextView) view.findViewById(R.id.text_img8_scrollview); mText4.setText(scrollText[7]); mText4 = (TextView) view.findViewById(R.id.text_img9_scrollview); mText4.setText(scrollText[8]); } catch (NullPointerException ne) { System.out.println("nullpointerexception ... TextView i metoden onPostExecute"); } alertadd.setView(view); alertadd.setNeutralButton("Here!", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dlg, int sumthin) { } }); alertadd.show(); break; } } /** * * @param options * @param reqW * @param reqH * @return */ public static int calculateInSampleSize(BitmapFactory.Options options, int reqW, int reqH) { int imageHeight = options.outHeight; int imageWidth = options.outWidth; int inSampleSize = 1; if (imageHeight > reqH || imageWidth > reqW) { int heightRatio = Math.round((float) imageHeight / (float) reqH); int widthRatio = Math.round((float) imageWidth / (float) reqW); inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; System.out.println("i if-satsen!"); System.out.println("height-ratio: " + heightRatio + "\nwidth-ratio: " + widthRatio); } System.out.println("samplesize: " + inSampleSize); inSampleSize = inSampleSize; return inSampleSize; } @SuppressLint("NewApi") /** * * @param res * @param resId * @param reqW * @param reqH * @return */ public static Bitmap[] decodeSampledBitmapFromResource(Resources res, int[] resId, int[] reqW, int[] reqH) { scaledBitmap = new Bitmap[resId.length]; BitmapFactory.Options options; for (int i = 0; i < resId.length; i++) { options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; Bitmap bm =BitmapFactory.decodeResource(res, resId[i], options); System.out.println("ursprunglig bild: h = " + options.outHeight + " w = " + options.outWidth); options.inSampleSize = calculateInSampleSize(options, reqW[i], reqH[i]); while (options.outHeight < reqH[i] || options.outWidth < reqW[i]) { options.inSampleSize--; System.out.println("räknar nu ner insampleseize\ninSamleSize =" + options.inSampleSize); } options.inJustDecodeBounds = false; bm = BitmapFactory.decodeResource(res, resId[i], options); System.out.println("innan omskalning: h = " + options.outHeight + " w = " + options.outWidth); System.out.println("antalet bytes: " + bm.getByteCount()); System.out.println("native free size: " + Debug.getNativeHeapFreeSize() ); scaledBitmap[i] = Bitmap.createScaledBitmap(bm, reqW[i], reqH[i], true); bm.recycle(); bm = null; } System.gc(); WeakReference <Bitmap[] > sc = new WeakReference <Bitmap[]> (scaledBitmap); return sc.get(); } }
}
- Posible alternativa a las clases internas estáticas para evitar fugas de memoria en android / java?
- Canal de entrada cerrado del consumidor o se produjo un error. eventos = 0x8
- ¿Es esta Runnable a salvo de fugas de memoria?
- Android dalvikvm-heap: Clamp objetivo GC montón
- Error de memoria insuficiente al reiniciar la aplicación (Android)
- Tamaño del montón de Android VM
- ¿Cómo utilizar los controladores?
- Error fatal: Adreno-GSL
Usted está manteniendo doble referencia a sus mapas de bits una vez débil y una vez copia de su código de problema es:
Bitmap[] bm = decodeSampledBitmapFromResource(sc.get().getResources(), data, width, height); bitmapV = new WeakReference <Bitmap[]> (bm);
Usted no está deshaciéndose del contenido de bm
Y lo estás haciendo más de una vez
scaledBitmap[i] = Bitmap.createScaledBitmap(bm, reqW[i], reqH[i], true); bm.recycle(); bm = null; } System.gc(); WeakReference <Bitmap[] > sc = new WeakReference <Bitmap[]> (scaledBitmap);
Usted debe hacer esto:
ArrayList<WeakReference<Bitmap>>scaledBitmaps= new ArrayList<WeakReference<Bitmap>>(); scaledBitmaps.add(new WeakReference<Bitmap>(Bitmap.createScaledBitmap...)); and do not use Bitmap[] array