Je reçois sporadiquement une OutOfMemoryError: (Heap Size=49187KB, Allocated=41957KB)
dans l'une de mes applications. Que puis-je faire pour diagnostiquer cela?
01-09 10:32:02.079: E/dalvikvm(8077): Out of memory: Heap Size=49187KB, Allocated=41957KB, Limit=49152KB
01-09 10:32:02.079: E/dalvikvm(8077): Extra info: Footprint=48611KB, Allowed Footprint=49187KB, Trimmed=7852KB
01-09 10:32:02.079: D/skia(8077): --- decoder->decode returned false
01-09 10:32:02.079: D/AndroidRuntime(8077): Shutting down VM
01-09 10:32:02.079: W/dalvikvm(8077): threadid=1: thread exiting with uncaught exception (group=0x40a97228)
01-09 10:32:02.079: E/AndroidRuntime(8077): FATAL EXCEPTION: main
01-09 10:32:02.079: E/AndroidRuntime(8077): Java.lang.OutOfMemoryError: (Heap Size=49187KB, Allocated=41957KB)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.Java:486)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.graphics.drawable.Drawable.createFromResourceStream(Drawable.Java:773)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.content.res.Resources.loadDrawable(Resources.Java:2044)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.content.res.Resources.getDrawable(Resources.Java:675)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.view.View.setBackgroundResource(View.Java:11776)
01-09 10:32:02.079: E/AndroidRuntime(8077): at com.blsk.bigtoss.ImageLoader.DisplayImage(ImageLoader.Java:81)
01-09 10:32:02.079: E/AndroidRuntime(8077): at com.blsk.bigtoss.MatchActivity$MatchAsyncTask.onPostExecute(MatchActivity.Java:1768)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.os.AsyncTask.finish(AsyncTask.Java:602)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.os.AsyncTask.access$600(AsyncTask.Java:156)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.Java:615)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.os.Handler.dispatchMessage(Handler.Java:99)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.os.Looper.loop(Looper.Java:156)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Android.app.ActivityThread.main(ActivityThread.Java:4987)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Java.lang.reflect.Method.invokeNative(Native Method)
01-09 10:32:02.079: E/AndroidRuntime(8077): at Java.lang.reflect.Method.invoke(Method.Java:511)
01-09 10:32:02.079: E/AndroidRuntime(8077): at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:784)
01-09 10:32:02.079: E/AndroidRuntime(8077): at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:551)
01-09 10:32:02.079: E/AndroidRuntime(8077): at dalvik.system.NativeStart.main(Native Method)
01-09 10:32:02.099: E/EmbeddedLogger(1612): App crashed! Process: com.blsk.bigtoss
01-09 10:32:02.099: E/EmbeddedLogger(1612): App crashed! Package: com.blsk.bigtoss v6 (1.2)
01-09 10:32:02.129: E/EmbeddedLogger(1612): Application Label: Cricket
C'est la ligne où cela se produit:
LinearLayout resultMatchHeaderContainer = new LinearLayout(activity);
if (!resultImagePath.equals("")) {
imageLoader.DisplayImage(resultImagePath,resultMatchHeaderContainer, -1,modifiedHeight, R.drawable.matches_placeholder_result2x);
} else {
try {
resultMatchHeaderContainer.setBackgroundResource(R.drawable.matches_placeholder_result2x);
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
}
peut-être que cela vous aide?
ajouter un manifeste
Android> v3
<application
....
Android:largeHeap="true">
Essayez d'utiliser le contexte approprié: par exemple, comme un Toast peut être vu dans de nombreuses activités au lieu d'une seule, utilisez getApplicationContext()
pour les toasts, et puisque les services peuvent continuer à fonctionner même si une activité est terminée, démarrez un service avec :
Intent myService = new Intent(getApplicationContext(), MyService.class)
Utilisez ce tableau comme guide rapide pour déterminer le contexte approprié:
Original article sur le contexte ici .
Par exemple, j'ai un intentionService qui utilise l'API du service de localisation Google. Et j'ai oublié d'appeler googleApiClient.disconnect();
:
//Disconnect from API onDestroy()
if (googleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, GoogleLocationService.this);
googleApiClient.disconnect();
}
Si vous utilisez la bibliothèque Picasso de Square , j'ai constaté que je perdais de la mémoire en n'utilisant pas la .fit()
, ce qui a considérablement réduit l'empreinte mémoire de 50 Mo en moyenne à moins de 19 Mo:
Picasso.with(ActivityExample.this) //Activity context
.load(object.getImageUrl())
.fit() //This avoided the OutOfMemoryError
.centerCrop() //makes image to not stretch
.into(imageView);
Java.util.Observer
(Modèle d'observateur):Assurez-vous d'utiliser deleteObserver(observer);
Vous pouvez faire ce qui suit pour éviter cela.
Drawable drawable = resultMatchHeaderContainer.getDrawable();
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable != null) {
Bitmap bitmap = bitmapDrawable.getBitmap();
if (bitmap != null && !bitmap.isRecycled())
bitmap.recycle();
}
}
Le chargement de Bitmap dans Imageview a toujours été une cause de problème de manque de mémoire, il est très courant, nous devons donc manipuler très attentivement imageview et bitmaps. Ce que vous pouvez faire, c'est tout en définissant une image bitmap d'arrière-plan sur votre image, commencez par obtenir le dessin et recyclez-le afin qu'il soit supprimé de la mémoire, puis définissez la nouvelle image bitmap. Cela vous aidera à éviter tout problème de MOO. Plus loin. Vous pouvez utiliser BitmapFactoryOptions pour réduire la taille de votre bitmap. comme:
// decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
try {
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1 = new FileInputStream(f);
BitmapFactory.decodeStream(stream1, null, o);
stream1.close();
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_WIDTH
|| height_tmp / 2 < REQUIRED_HIGHT)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
FileInputStream stream2 = new FileInputStream(f);
Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Avant de charger des images en mémoire, compressez vos images à l'aide
Bitmap original = BitmapFactory.decodeStream(getAssets().open("1024x768.jpg"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
original.compress(Bitmap.CompressFormat.PNG, 100, out);
Bitmap decoded = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));
Log.e("Original dimensions", original.getWidth()+" "+original.getHeight());
Log.e("Compressed dimensions", decoded.getWidth()+" "+decoded.getHeight());
Si vous obtenez votre bitmap à partir d'une ressource, auquel cas la dimension bitmap dépendra de la densité de l'écran du téléphone
Bitmap bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.img_1024x768)).getBitmap();
Log.e("Dimensions", bitmap.getWidth()+" "+bitmap.getHeight());
Cela peut se produire pour plusieurs raisons, vous conservez peut-être trop longtemps les références à d'autres parties de votre code. Vous pouvez être en train de charger sur de grandes images bitmap qui, avec s'accrochent à de nombreuses références vous donne un MOO, etc.
Normalement, lorsqu'un MOO se produit, un hprof (instantané du tas) est créé à la racine de la carte SD (ou du stockage interne si la carte SD n'existe pas), qui peut être lu par des outils comme Eclipse MAT (inclus dans les outils Android si vous utilisez Eclipse). Premier pourrait avoir besoin de convertir le hprof avec hprof-conv
outil. Voici un didacticiel sur la façon d'utiliser Eclipse MAT: Investigating Your RAM Usage . Le rapport sur les suspects de fuite est une bonne première lecture lorsque hprof est chargé dans Eclipse MAT
Après le profilage, vous pouvez lire comment charger efficacement des images à partir de Affichage efficace des bitmaps
Il existe également plusieurs bibliothèques de chargement d'images populaires telles que chargeur d'image universel et picasso disponibles, qui font facilement ce dont vous avez besoin.
sourire Bitmap final = BitmapFactory.decodeResource (getResources (), R.drawable.Emo_im_happy);
Appel
String pathname=BitMapToString(smile);
puis appeler
setImagesNew(linearview,pathname,activity);
...
public String BitMapToString(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
String temp = Base64.encodeToString(b, Base64.DEFAULT);
return temp;
}
public static void setImagesNew(LinearLayout linearLayout, String pathName,
Activity activity) {
Bitmap bmp = decodeSampledBitmapFromResource(pathName,
getDeviceWidth(activity), getDeviceHeight(activity));
linearLayout.setBackgroundDrawable(bmp);
bmp = null;
System.gc();
Runtime.getRuntime().gc();
}
public static Bitmap decodeSampledBitmapFromResource(String pathName,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(pathName, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and
// keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
@SuppressLint("NewApi")
public static int getDeviceWidth(Activity activity) {
int deviceWidth = 0;
Point size = new Point();
WindowManager windowManager = activity.getWindowManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
windowManager.getDefaultDisplay().getSize(size);
deviceWidth = size.x;
} else {
Display display = windowManager.getDefaultDisplay();
deviceWidth = display.getWidth();
}
return deviceWidth;
}
@SuppressLint("NewApi")
public static int getDeviceHeight(Activity activity) {
int deviceHeight = 0;
Point size = new Point();
WindowManager windowManager = activity.getWindowManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
windowManager.getDefaultDisplay().getSize(size);
deviceHeight = size.y;
} else {
Display display = windowManager.getDefaultDisplay();
deviceHeight = display.getHeight();
}
return deviceHeight;
}
veuillez mettre toutes les fonctions dans votre activité et appeler uniquement setImageNew()
et passer le paramètre dans imageview, sdcardpathname et activity
J'espère qu'il ne plantera pas après avoir implémenté ce code. parce que je me pose le même problème que toi ..
Cela peut se produire si la ressource bitmap n'est pas supprimée correctement. Il est préférable de lire les dimensions pour voir si cela correspond à la mémoire. http://developer.Android.com/training/displaying-bitmaps/load-bitmap.html