I have a Xamarin.Android application who contains a lot of button in her main game activity (25+).
When I press on a button, I randomly get a crash on my application. I have the following logs for the crash :
Xamarin caused by: java.lang.OutOfMemoryError: Failed to allocate a 44236812 byte allocation with 8344256 free bytes and 7MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:856)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:675)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:2228)
at android.content.res.Resources.loadDrawableForCookie(Resources.java:4211)
at android.content.res.Resources.loadDrawable(Resources.java:4085)
at android.content.res.Resources.getDrawable(Resources.java:2005)
at android.content.res.Resources.getDrawable(Resources.java:1987)
at android.content.Context.getDrawable(Context.java:464)
at android.view.View.setBackgroundResource(View.java:18532)
at mono.android.view.View_OnClickListenerImplementor.n_onClick(Native Method)
at mono.android.view.View_OnClickListenerImplementor.onClick(View_OnClickListenerImplementor.java:29)
at android.view.View.performClick(View.java:5702)
at android.widget.TextView.performClick(TextView.java:10888)
at android.view.View$PerformClick.run(View.java:22541)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
I do not know what really happends and how to fix it. An interested fact is that when I install the app, I did not face any issue the first time I use it. If I close the app and restart it, I get random crash on a button click event. The button action is to set a différent background image on a ImageView.
You can find a snapshot of my method who change the background :
private void SetErrorImage(ImageView component, int errorNumber)
{
switch (errorNumber)
{
case 0:
component.SetBackgroundResource(Resource.Drawable.arbre_00);
break;
case 1:
component.SetBackgroundResource(Resource.Drawable.arbre_01);
break;
case 2:
component.SetBackgroundResource(Resource.Drawable.arbre_02);
break;
case 3:
component.SetBackgroundResource(Resource.Drawable.arbre_03);
break;
case 4:
component.SetBackgroundResource(Resource.Drawable.arbre_04);
break;
case 5:
component.SetBackgroundResource(Resource.Drawable.arbre_05);
break;
case 6:
component.SetBackgroundResource(Resource.Drawable.arbre_06);
break;
case 7:
component.SetBackgroundResource(Resource.Drawable.arbre_07);
break;
}
}
Following this link, is it possible to use something like this Java method in Xamarin ?
((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();
Not the reason where your app looses the memory but a way to make OutOfMemoryError less likely.
I see that android wants to allocate "44236812" bytes (44 Megabytes) for an uncompressed image that may come from a 2048*1536 pixel 1.6MB jpg file.
Have you tried to reduce your resource images (less pixels or less bits per pixel)? Is your device capable to display this high resolution?
As you kinda thought, you need to free the images properly.
Even just changing the orientation several times, will just allocate more and more memory, if you dont free it properly.
Basically just
imageView.SetImageDrawable(null)
should do the trick.
Related
I have got a strange memory leak on samsung devices. If I do a lot of navigations then it produces an OutOfMemoryException with this StackTrace:
Exception: Failed to allocate a 276060 byte allocation with 184864 free bytes and 180KB until OOM
StackTrace:
--- End of managed Java.Lang.OutOfMemoryError stack trace ---
java.lang.OutOfMemoryError: Failed to allocate a 276060 byte allocation with 184864 free bytes and 180KB until OOM
**at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:977)
at android.graphics.Bitmap.createBitmap(Bitmap.java:948)
at android.graphics.Bitmap.createBitmap(Bitmap.java:915)
at android.widget.TextView$MagnifierView.getContentsBitmap(TextView.java:14862)
at android.widget.TextView$MagnifierView.<init>(TextView.java:14806)
at android.widget.TextView.getMagnifierView(TextView.java:14707)**
at android.widget.Editor.onDetachedFromWindow(Editor.java:469)
at android.widget.TextView.onDetachedFromWindowInternal(TextView.java:6224)
at android.view.View.dispatchDetachedFromWindow(View.java:16766)
at android.view.ViewGroup.removeAllViewsInLayout(ViewGroup.java:5154)
at md58b29b5ebe7ec5add1ba4eaa7f6c6bb96.EventDetailsView_1.n_onDestroy(Native Method)
at md58b29b5ebe7ec5add1ba4eaa7f6c6bb96.EventDetailsView_1.onDestroy(EventDetailsView_1.java:47)
at android.app.Activity.performDestroy(Activity.java:7210)
at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1161)
at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4621)
at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4661)
at android.app.ActivityThread.-wrap7(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1703)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
Does anybody have an idea what these lines (See below) do and why the hell it allocates memory (Bitmap) when it is being destroyed?
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:977)
at android.graphics.Bitmap.createBitmap(Bitmap.java:948)
at android.graphics.Bitmap.createBitmap(Bitmap.java:915)
at android.widget.TextView$MagnifierView.getContentsBitmap(TextView.java:14862)
at android.widget.TextView$MagnifierView.<init>(TextView.java:14806)
at android.widget.TextView.getMagnifierView(TextView.java:14707)**
As far I understand from my testing, the activities are kept in memory even after OnDestroyed or Finish are called. If I navigate back and wait a minute I see the free memory is climbing again. Otherwise, the allocated memory get's bigger and at some point there is not enough space to do another navigation so the system tries to free memory by destroying an old activity. But this activity is allocating memory (MagnifierView) which isn't free during the Destroy-Process.
When I do the same on a Xperia Z5, the memory is freed right after a back navigation.
I am trying to load a jpeg photo with a size of 965KB on my android phone. The code is below. When I run the code, the app crashes.
Button _btn = (Button) findViewById(R.id.btn1);
_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Drawable _draw = getResources().getDrawable(R.drawable.sea, null);
}
});
This is the crash log.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.a3sumatch.multipart, PID: 29240
java.lang.OutOfMemoryError: Failed to allocate a 362797068 byte
allocation with 8388608 free bytes and 254MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
at
android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
at
android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1080)
at
android.content.res.Resources.loadDrawableForCookie(Resources.java:2761)
at android.content.res.Resources.loadDrawable(Resources.java:2654)
at android.content.res.Resources.getDrawable(Resources.java:833)
at
com.a3sumatch.multipart.MainActivity$1.onClick(MainActivity.java:40)
at android.view.View.performClick(View.java:5205)
at android.view.View$PerformClick.run(View.java:21176)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:171)
at android.app.ActivityThread.main(ActivityThread.java:5611)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:732)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
I am trying to load a jpeg photo with a size of 965KB on my android phone
That is an absolutely massive photo. JPEG, like PNG and WebP, is a compressed file format. To put that in perspective, a 3229x2480 photo of my balding head is 829.3KB in a JPEG. I would expect yours to be a bit larger in each dimension. That resolution is higher than the resolution of any Android device screen that I know of.
Your OutOfMemoryError is for a 362797068-byte allocation. A Bitmap is an uncompressed version of the image. 362797068 bytes is equivalent to about a 9524x9524 square image (and 4 bytes/pixel).
So, you need to do two things:
If you have this image in res/drawable/, move it to res/drawable-nodpi/
Reduce the resolution of this image by at least a factor of four along each dimension
I want to change the background image of my Activity's layout every time I launch that activity. For that reason, inside onResume(), I am randomly setting the background image of layout like this:
#Override
public void onResume(){
super.onResume();
Random r = new Random();
int randNumber = r.nextInt(homeBackgroundImage.length);
mBackgroundLayout.setBackground(ResourcesCompat.getDrawable(getResources(), homeBackgroundImage[randNumber], null));
}
But, I am getting exception in the following line:
mBackgroundLayout.setBackground(ResourcesCompat.getDrawable(getResources(), homeBackgroundImage[randNumber], null));
This is the logcat output:
java.lang.OutOfMemoryError: Failed to allocate a 756946956 byte allocation with 16777216 free bytes and 433MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1080)
at android.content.res.Resources.loadDrawableForCookie(Resources.java:2635)
at android.content.res.Resources.loadDrawable(Resources.java:2540)
at android.content.res.Resources.getDrawable(Resources.java:806)
at android.support.v4.content.res.ResourcesCompatApi21.getDrawable(ResourcesCompatApi21.java:27)
at android.support.v4.content.res.ResourcesCompat.getDrawable(ResourcesCompat.java:60)
at in.avara.app.avaravrplayer.Activity.MainActivity.onResume(MainActivity.java:167)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1258)
at android.app.Activity.performResume(Activity.java:6327)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3092)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3134)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2481)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Someone, please suggest me What is the optimized and best way to change background image of a layout randomly on every launch.
NOTE: I have already tried adding android:hardwareAccelerated="false" , android:largeHeap="true". But, it didn't work in my case.
Thanks in advance!
You are attempting to allocate 756946956 bytes ~= 721MB. This is much too large.
Moreover, 756946956 bytes represents the equivalent of a 13756 x 13756 pixel image. This is far larger than any Android screen.
You need to identify the image that is failing and reduce its resolution significantly.
If you put this image in res/drawable/, bear in mind that res/drawable/ is a synonym of res/drawable-mdpi/. Your image will be upsampled when you use that drawable on higher screen densities (e.g., xhdpi). You probably should move that drawable out of res/drawable/ and into either a density-specific directory for the desired density (e.g., res/drawable-xhdpi/), or into res/drawable-nodpi/ to disable this density-based resampling.
Try to put move your images from res/drawable/ to res/drawable/drawable-nodpi. If problem is still here, in your manifest under application put android:largeHeap="true".
The relevant code:
runOnUiThread(new Runnable() {
#Override
public void run() {
ImageButton btn = (ImageButton) findViewById(R.id.info_image);
btn.setImageResource(currentID[currentIDPos]);
}
});
It's saying that the run method is making a 400-some megabyte allocation. My jpgs are no more than a megabyte in size. The run() method is called on a timer every 3-4 seconds or so and on click, but that shouldn't matter because from what I can tell using printlns the run() is only called once before the crash.
Edit: Here's the exception. Had to run it again to get this, it's a different amount of memory this time but still very large.
FATAL EXCEPTION: main
Process: com.grey.handsaver, PID: 32531
java.lang.OutOfMemoryError: Failed to allocate a 215151564 byte allocation with 33554400 free bytes and 100MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:988)
at android.content.res.Resources.loadDrawableForCookie(Resources.java:2580)
at android.content.res.Resources.loadDrawable(Resources.java:2487)
at android.content.res.Resources.getDrawable(Resources.java:814)
at android.content.res.XResources.getDrawable(XResources.java:572)
at android.content.Context.getDrawable(Context.java:403)
at android.widget.ImageView.resolveUri(ImageView.java:747)
at android.widget.ImageView.setImageResource(ImageView.java:398)
at com.grey.handsaver.ExerciseInfoActivity$3.run(ExerciseInfoActivity.java:128)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5430)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:913)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:706)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:115)
Try to use picasso library for loading large image.it's having inbuilt cache functionality.
Step 1:
First write follow code in gradle.build and sync gradle.
compile 'com.squareup.picasso:picasso:2.5.2'
Step 2:
Picasso.with(context).load("YOUR IMAGE PATH").into(btn);
and write above code where we load the image.in this code you must need to provide image path and make sure image path is valid.if you really want to learn something more about this Library than please Visit this.
I hope your are clear with my Idea.
Best of Luck
Most likely the issue is that you are not clearing up the previously allocated space. Are you sure that the fragment/activity that loads these pictures is also removed from backstack? Or maybe the images themselves are not being garbage collected?
Re-do the same steps that are causing the OutofMemory Exception but make sure to switch to Memory Monitor Tab in Android Studio and check where the Memory is increasing drastically but not being freed when it should be. This should give you a head start to see where the memory leak might be.
Also possible that there is no leak, rather your pictures themselves are huge (although doesnt seems to be). In this case you should do lazy loading, cache implementation etc. or just use some third party library like Picasso which handle this for you
Alright, I figured it out. I'm using an lg g4, which uses xxxhdpi, and my images were in the drawable folder, not the drawable-xxxhdpi folder. This solved my problem without using picasso or the other methods.
I have a WebView that shows a bitmap from uri. It works well the first 7 or 8 times it is loaded but then when loading it i get this error. Need help please.
01-27 18:44:27.155 30480-30480/? E/dalvikvm-heap﹕ Out of memory on a 631816-byte allocation.
01-27 18:44:30.579 15859-15859/? E/MtpService﹕ In MTPAPP onReceive:android.intent.action.BATTERY_CHANGED
01-27 18:44:30.579 15859-15859/? E/MtpService﹕ battPlugged Type : 2
01-27 18:44:34.362 1704-8058/? E/Dumper﹕ 3: 48387128549: User action: dump logging circular buffer and context
01-27 18:44:34.362 1705-2000/? E/Dumper﹕ 3: 48387128549: User action: dump logging circular buffer and context
01-27 18:44:34.362 1704-8058/? E/Dumper﹕ 4: 48387128579: Triggering circular buffer dump in /data/ste-debug
01-27 18:44:34.362 1705-2000/? E/Dumper﹕ 4: 48387128579: Triggering circular buffer dump in /data/ste-debug
01-27 18:44:35.023 30960-30971/? E/SQLiteLog﹕ (1) duplicate column name: EVENT_TYPE
01-27 18:44:35.123 2296-2296/? E/Launcher﹕ Error finding setting, default accessibility to not found: accessibility_enabled
Are you recycling your bitmaps? Could you reduce the size of the images?
Please look at these links:
Strange out of memory issue while loading an image to a Bitmap object
Large images in WebView cause Out Of Memory
webview capturing causes out of memory exception
Have you considered implementing onLowMemory() and using freeMemory on the WebView? You could also use clearCache. Another consideration would be to change the cache mode.