アプリの1つでOutOfMemoryError: (Heap Size=49187KB, Allocated=41957KB)
を散発的に取得しています。これを診断するにはどうすればよいですか?
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
これはそれが起こっている行です:
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();
}
}
多分これはあなたを助ける?
マニフェストを追加
Android> v3
<application
....
Android:largeHeap="true">
適切なコンテキストを使用してみてください。たとえば、Toastは1つではなく多くのアクティビティで見ることができるので、トーストにはgetApplicationContext()
を使用します。 :
Intent myService = new Intent(getApplicationContext(), MyService.class)
このコンテキストを適切なコンテキストのクイックガイドとして使用します。
オリジナル コンテキストに関する記事はこちら 。
たとえば、Google Location Service APIを使用するintentServiceがあります。そして、googleApiClient.disconnect();
を呼び出すのを忘れました:
_//Disconnect from API onDestroy()
if (googleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, GoogleLocationService.this);
googleApiClient.disconnect();
}
_
正方形のライブラリPicassoを使用している場合、.fit()
を使用しないことでメモリリークが発生していることがわかりました。平均で50MBから19MB未満:
_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
_(オブザーバーパターン)を使用している場合:必ずdeleteObserver(observer);
を使用してください
これを回避するには、次のようにします。
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();
}
}
Imageviewでのビットマップの読み込みは常にメモリ不足の問題の原因であり、非常に一般的であるため、imageviewとビットマップを非常に慎重に処理する必要があります。あなたができることは、画像ビューに背景ビットマップを設定している間に、まずドロアブルを取得してリサイクルし、メモリから削除してから新しいビットマップを設定します。これにより、OOMの問題を回避できます。さらに。 BitmapFactoryOptionsを使用して、ビットマップのサイズを縮小できます。のような:
// 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;
}
画像をメモリにロードする前に、画像を圧縮します
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());
リソースからビットマップを取得する場合、その場合、ビットマップのサイズは電話の画面密度に依存します
Bitmap bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.img_1024x768)).getBitmap();
Log.e("Dimensions", bitmap.getWidth()+" "+bitmap.getHeight());
これはいくつかの理由で発生する可能性があります。コードの他の部分への参照が長すぎます。 多くの参照を保持するとともにOOMなどを提供する大きなビットマップにロードする可能性があります.
通常、OOMが発生すると、hprof(ヒープのスナップショット)がsdcard(またはsdcardが存在しない場合は内部ストレージ)のルートに作成され、Eclipse MAT(Eclipseを使用する場合はAndroidツールに含まれます)。最初にhprof-conv
ツールでhprofを変換する必要があるかもしれません。 Eclipse MATの使用方法のチュートリアルを1つ示します。 RAM使用状況の調査 。 リークの疑いのあるレポートは、hprofがEclipse MATにロードされたときに最初に読むのに適しています
プロファイリング後、 ビットマップを効率的に表示する から画像を効果的にロードする方法を読むことができます。
niversal image loader や picasso などの人気のある画像読み込みライブラリもいくつかあり、必要なことを簡単に実行できます。
最終ビットマップ笑顔= BitmapFactory.decodeResource(getResources()、R.drawable.Emo_im_happy);
コール
String pathname=BitMapToString(smile);
そして、呼び出します
_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;
}
_
すべての関数をアクティビティに入れて、setImageNew()
のみを呼び出し、imageview、sdcardpathnameおよびactivityでパラメータを渡してください
このコードを実装した後、クラッシュしないことを願っています。私はあなたと同じ問題を起こすからです。
これは、ビットマップリソースが正しく破棄されない場合に発生する可能性があります。メモリに適合するかどうかを確認するために、寸法を読むことをお勧めします。 http://developer.Android.com/training/displaying-bitmaps/load-bitmap.html