I have an activity that uses recyclerView and for each item's view there is an Image.
I have used Garbage Collector GC() on Destroy as follows
recyclerView= null;
adapter=null;
Runtime.getRuntime().gc();
But the following thing happens while releasing memory
And When I start another activity that loads images from a remote host using Picasso It says
java.lang.OutOfMemoryError: Failed to allocate a 94784012 byte allocation with 4194304 free bytes and 87MB until OOM
I found an answer that works for me to overcome that OutOfMemoryError
by Increasing heap size for application But I still want to release and ensure that memory occupied by an Activity is released instead of going to increase heap size for app.Thanks in advance , please help to do that task.
The code that you are using in your onDestroy method is not needed there. If destroy is called your acitivity will be removed from the stack and is free for gc anyway with all the resources in it that are only referenced by the activity.
OnDestroy doesn't always get called that's why your method may not be called at all. You could try and explicitly call for finish() in activity then onDestroy will be called and see how the situation will change.But then the activity will be removed from stack.
Also to call for gc manually is supposed to be bad style. On Android the system nearly always knows when it is the best time to do a garbage collection. Most of the times an activity finishes garbage collection is triggered automatically.
I would look into resizing images you get from Picasso first as they just could be too big in general for you heap even if there is space.
Look into resizing options link
Seems the problem is related to huge images, try to not keep images in memory, load images only on demand(with some cache strategy)
Try to replace picasso with glide. Glide provides better memory performance https://medium.com/#multidots/glide-vs-picasso-930eed42b81d
Try to load all your images with closest context
https://stackoverflow.com/a/32887693/6193843
Related
1)It is considered a good tactic to recycle all bitmaps and data at activity's OnStop method.
2)It's also considered a good tactic to use a retainer Fragment to avoid recreating data at every configuration change.
But I don't see how these two can be combined?
Let's say I use a fragment to load a bunch of bitmaps...At OnCreate I check if that Fragment is null or not to get it's data or to instantiate a new one to create them. If i recycle all my bitmaps at OnStop() then there will be nothing left retrieve at the configuration change cause all data will have been recycled.
So....I don't see any way to combine these two tactics. Am I wrong? And if not which of the two is best to use?
My case is about loading images from SD card folder. could be only one pic, could be 500...
and showing pictues isn't all my app does so after this activity there could a need for memory by some other activity.
From Managing Bitmap Memory:
On Android 2.3.3 (API level 10) and lower, using recycle() is
recommended. If you're displaying large amounts of bitmap data in your
app, you're likely to run into OutOfMemoryError errors. The recycle()
method allows an app to reclaim memory as soon as possible.
According to this you don't even need to call recycle on devices running API 11 or higher, so it may not really be a problem for you.
You also really don't need to recycle bitmaps if the app is being destroyed as the system is going to reclaim all memory the app is taking up to begin with.
Recycle is only needed if you are showing a massive amount of bitmaps or large bitmaps and need the memory reclaimed in your app while it's still running.
Another thing to note is with the strategy you're trying, you wouldn't clean resources in the Activity's onStop() but rather the retained Fragment's onDestroy(). OnDestroy() on a retained fragment won't be called on configuration change because the Fragment isn't ever being destroyed. Thus, your resources can stay in memory beyond your Activity's lifecycle and will be destroyed at the end of your Application's lifecycle.
I have a ViewPager with a couple of fragments. In a fragment onCreateView,
I decode a couple of bitmaps that are assigned to fields in the Fragment class. If I try to swipe between the fragments, at a certain point the application gets an OutOfMemory exception (heap is exhausted).
Ok, this is a really bad practice, but, isn't the GC supposed to free memory before my application is killed?
Reassigning the Bitmap to the same field should cause the previous Bitmap to be released, am I wrong? On S4 I get the exception very soon.
Suppose you load a bitmap, lets say that is the first and then assign a new decoded second bitmap to the first, the first bitmap is not GC'ed when you decode the second one. GC will do it later whenever it decides. If you want to free memory ASAP you should call recycle() just before decoding the second bitmap. Src: here. And, go through Android's Managing Bitmap Memory article. Refer this too.
Fragments are kept in memory unless stated otherwise, so either you manually detach and dispose of fragments when swiping or mBitmap.recycle() when swiping.
Edit, code:
final FragmentTransaction fm = getActivity()
.getSupportFragmentManager().beginTransaction();
fm.replace(R.id.fragPlayerMain, playerFragment, "fragment").addToBackStack(null);
fm.hide(thisFrag);
fm.detach(thisFrag);
fm.commitAllowingStateLoss();
In my APP, Activity-A triggers another Activity-B. Activity-B triggers another Activity-C. Now the control return to the Activity-A from Activity-C Via Activity-B. The Activity-A uses the Bitmap image to draw as a background in its Canvas.
Question:
When I move from Activity-A to B, Do I need to recycle the bitmap variable (eg. background.recycle()) in onPause() method ?
Assume, I recycled the bitmap variable in onPause() method. Will this be a good approach to avoid OOM error ( keep in mind that the image has to be re-drawn when it comes back to Activity-A)
Do you get OOM errors? If not (since your bitmap is not big) then simply do nothing ... The docu says about the recycle method:
This is an advanced call, and normally need not be called, since the
normal GC process will free up this memory when there are no more
references to this bitmap.
So there is also a main difference between Android 2.x and Android 4.x. In Android 4 the bitmap memory is no longer managed natively, but is part of the normal java heap and works like every reference works: If the there is no reference anymore, then the garbage collector will collect the bitmap somewhere in the future.
Wherer is the right point to call recycle? Well the right point will be, when the Bitmap is no longer displayed on screen. so onPause could be a possibility, but keep in mind that you have to reload it (async) in onResume. So whats the problem with that approach? Once you have marked the Bitmap to be no longer needed by calling recycle() the bitmap is no longer useable, but probably has not been GC collected yet. So if the user jumps from Activty A to B and will return quickly, it's possible, that you have the same bitmap twice in memory, because the GC has not collected yet the first (recycled) bitmap.
So my tipp is: Try to reduce the bitmap size if you have memory issues. Use less quality bitmap (have a look at Bitmap Options). But I guess you need to try diffrent strategies to find the best working one for your app.
every time you don't need the bitmap recycle it. using
if method at least to avoid force closing in some cases.
if (null != bmp){
bmp.recycle();
}
and i advice you instead of sending the Bitmap between activities get its filename by using intent and pass it through your activities like this you will avoid re-drawing the bitmap in every activity and that will cause OOM for sure.
First I'm using API 10.
I have activity A and activity B.
I launch activity B from A. Then I call finish() in the oncreate() of B. I then launch activity B from A again and so on. When i do this my native heap keeps increasing by about .5 MB every time.
This is the only code I have in activity B.
super.onCreate(savedInstanceState);
getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);
logHeap(); //keeps track of native heap size
setContentView(R.layout.gameplay);
finish();
return;
Are the bitmaps in layout not getting recycled? I don't understand why my native heap size would keep increasing.
You should make sure you're calling bitmap.recycle() when you no longer need the Bitmap. It may take some time for the Bitmap to be recycled by GC.
Found most of it.
Apparently creating from assets
Typeface tf = Typeface.createFromAsset(getAssets(),"fonts/Capture_it.ttf");
isn't garbage collected.
Removing it seemed to fix most of the problem.
Not exactly an answer, but a way to get an answer. If you use MAT (http://www.eclipse.org/mat/) in Eclipse and debug your app, you might find out what exactly is causing the growth in your app's native heap use.
Additionally: from Eclipse, if you access the DDMS, you might be able to use the techniques described here to view which objects are growing.
I'm working on an application which has about 4 to 5 HorizontalScrollViews. Out of these, 3 are completely loaded with images. To get this working I had to overcome java.lang.OutOfMemoryError, many times. Thanks to all the friends on stackoverflow. Now, my next activity is again going to be filled, completely, with images. Therefore, I wanted to know whether heap is freed when a new activity begins?
If you will kill the previous activuty using finish() then it will not use heap memory else it will us else memory being in the background(stack).