Memory not freeing after fragment is removed
Asked Answered
C

2

14

I have a Fragment which has a RecyclerView.

In this RecyclerView, I may occasionally download and display images (loaded with Glide into ImageView.

So when I open the Fragment, used memory may sometimes jump from around 30MB to around 100MB or even more.

After the Activity that is holding the Fragment is finished, the memory does not free up. It stays the same as before.

I checked Glide documentation and apparently we don't have to worry about freeing up Bitmaps in RecyclerView. This is a huge issue, because app often crashes due to OOM because of this.

How should I correctly handle freeing up memory when Fragment is removed?

Edit: another observation

Another thing I noticed is that if I finish the Activity and then start the same Activity again. Memory will jump back down for a moment and then back up to 100MB, which leads me to believe that the memory is cleared before launching the Fragment again.

Create answered 26/7, 2016 at 14:10 Comment(0)
L
10

Garbage Collection is sometimes a painful issue in Android. Most developers fail to consider this issue and just keep developing without any sense of resource allocation.

This will of course cause memory problems such as leaks, OOM and unnecessary resource binding. There is absolutely no automatic way to free up memory. You can not, under any circumstances, rely solely on the Garbage Collector

Whenever you pass the Fragment's or Activity's onDestroy() method, what you can and should do is erase any construct that shall no longer be required in the application. You can do the following :

  1. Avoid anonymous instances of listeners. Create listeners and destroy them when you no longer need them.
  2. Set all the listeners (be them click, longclick, etc) to null
  3. Clear all variables, arrays. Apply the same procedure to all the classes and subclasses contained inside the Activity/Fragment
  4. Set the variable to null whenever you perform any of the previous steps on that given class (applies to all variables)

What I ended up doing was creating an interface like

public interface clearMemory(){
    void clearMemory();
}

and implementing it on every class, be it Activity, Fragment or a normal class (includes adapters, custom views, etc).

I would then call the method whenever the class was to be destroyed (because the app was being destroyed or whenever I felt need to do so. Careful not to dispose in normal runtime)

@Override
public void onDestroy(){
    clearMemory();
}

public void clearMemory(){
    normalButtonOnClickListener = null;
    normalButton.setOnClickListener(null);
    normalButton = null;
    myCustomClass.clearMemory(); // apply the interface to the class and clear it inside
    myCustomClass = null;
    simpleVariable = null;
    ...        
}

By implementing this in a systematic way, my applications' memory management has become easier and leaner. One can then then know/control exactly how and when the memory is disposed.

Lymphoblast answered 26/7, 2016 at 17:1 Comment(5)
Thanks, this definitely does help. I will give this a try tomorrow (although it may take a while before I do this throughout the app) and I will let you know how it went.Create
When you said to clear all variables, that means instance variables, right? If I create a variable in onCreate method, should I also clear that one after I stop using it?Create
Yes. Everything that you allocate must/should be dealt with as soon as you know you wont need it anymore. As a metaphor : 1) You buy a piece of disposable paper. You write on that piece of paper a few facts about your day 2) You will use that piece of paper for the whole day but you know you wont need the paper forever 3) By the end of the day, you realize the paper has now fulfilled it's purpose. 4) You discard the paper by tearing it apart and throwing it to the garbage can. Now, understand "piece of paper" as any variable that you use and your "day" as your activity lifecycle.Lymphoblast
Looks like I have a lot of code refactoring to do then :) thanks! One additional question. what do you think is the best place to dispose of variables in Fragment? I understand that onDestroy and onDestroyView may not always be called. So right now, I'm doing it on onStop. Is that ok?Create
Excellent remark. Take a look at this other StackOverflow post : #19609448 Regards!Lymphoblast
C
4

This is adding on to Ricardo's answer.

You can add the following code to initiate garbage collection in Android:
Runtime.getRuntime().gc();

Note: Call this function after you've made all local variables null. Execution of this code doesn't guarantee that the system will garbage collect on your app, it merely hints that it might be a good time to do it.
I've used this in all my activities' onDestroy(), and it always seems to work when I want it to.
Give it a try, it might help you out.

Catholicism answered 26/7, 2016 at 17:12 Comment(3)
Exactly. One can basically call System.gc() to "hint" the system, and it will eventually execute to collect all objects without references. A controlled memory management is always an essential part of any application!Lymphoblast
This answer is really helpful for me. I have been trying to clear resources on destroy but only memory is reduced after initiate garbage collection. Thanks.Walking
what happens if i call garbage collector after every popbackstack ?Indecisive

© 2022 - 2024 — McMap. All rights reserved.