When a Fragment Is Replaced and Put in the Back Stack (Or Removed) Does It Stay in Memory

When a Fragment is replaced and put in the back stack (or removed) does it stay in memory?

Take a look at this: BackStackRecord.Op.fragment

That is how fragments are stored in the back stack. Note the live reference, neither WeakReference nor SoftReference are used there.

Now this: FragmentManagerImpl.mBackStack

That is where manager stores the back stack. Simple ArrayList, also, no WRs or SRs.

And finally this: Activity.mFragments

That is the reference to the fragment manager.

GC can only collect objects that have no live references (are not reachable from any thread). That means, until your Activity is destroyed (and so, FragmentManager reference is gone), GC will not be able to collect any of the Fragments in the back stack.

Note that when Activity is destroyed and retains state (like when you turn the device to landscape mode), it doesn't retain actual Fragment objects in the stack, only their states - Fragment.FragmentState objects, i.e. actual fragments in the back stack are re-created every time activity gets re-created with retained state.

Hope this helps.

PS So, in short: Yes, you can run out of memory by adding Fragments to back stack as well as by adding too many views to view hierarchy.

UPD Considering your example, F will stay in memory until C is killed. If C is killed and then resurrected with different configuration - F will be destroyed and reincarnated in a different object as well. So, F's memory footprint is around until C loses state or back stack is cleared.

What happens when a fragment called from backstack?

I believe what you are trying to ask is about the lifecycle of the Fragment and how GC work's for Fragment in the back-stack.

From my observation and knowledge when you add a Fragment to the backstack then Fragment is in the RAM of the device but if there are many number of task(Fragment)
alive then GC might do a force destroy of the Fragment based on the need.

For better understanding of the fragment lifecycle and what happens to the Fragment in Backstack refer this Flow chart.

This diagram might be little complex but it will help you understand how fragment work's.

NOTE: when you pop/replace a fragment then the fragment itself is destroyed you can check it by keeping a breakPoint at onDestroy() of the Fragment.

Fragment lifeCycle

If image is not available refer here

How can I maintain fragment state when added to the back stack?

If you return to a fragment from the back stack it does not re-create the fragment but re-uses the same instance and starts with onCreateView() in the fragment lifecycle, see Fragment lifecycle.

So if you want to store state you should use instance variables and not rely on onSaveInstanceState().

Backstack and memory leakage

Yes, its prone to low memory, not memory leak though. All back stack Fragment are kept in memory with hard references. So if you are keeping a ridiculous amount of Fragments in back stack then you will get out of memory.

Have a look here: When a Fragment is replaced and put in the back stack (or removed) does it stay in memory?

UPDATE: I see your DIALOG_TAG is not changing so you are keeping only one Fragment in backstack at a time, because you remove old one if it exists. In this case you might not have the issue of low memory.

FragmentTransaction, Frame Container, Freeing Fragments and Memory Management

Until your activity dies, all the references to its fragments will
exist in memory. Regardless of add/remove operations that happened at
Fragment Manager level / backstack.

Have a look on this stack overflow answer by Martín Marconcini.

A work around can be hiding and showing the frgaments if they exists in the back stack.
Have a look on the this.

Android Fragments on Backstack taking up too much memory

It turns out that fragments share the same lifecycle as their parent activity. According to the Fragment documentation:

A fragment must always be embedded in an activity and the fragment's
lifecycle is directly affected by the host activity's lifecycle. For
example, when the activity is paused, so are all fragments in it, and
when the activity is destroyed, so are all fragments. However, while
an activity is running (it is in the resumed lifecycle state), you can
manipulate each fragment independently.

So the step that you took to clean up some resources in onPause() of the fragment wouldn't trigger unless the parent activity pauses. If you have multiple fragments that are being loaded by a parent activity then most likely you are using some kind of mechanism for switching which one is active.

You might be able to solve your issue by not relying on the onPause but by overriding setUserVisibleHint on the fragment. This gives you a good place to determine where to do your setup of resources or clean up of resources when the fragment comes in and out of view (for example when you have a PagerAdapter that switches from FragmentA to FragmentB).

public class MyFragment extends Fragment {
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
//you are visible to user now - so set whatever you need
initResources();
}
else {
//you are no longer visible to the user so cleanup whatever you need
cleanupResources();
}
}
}

As was already mentioned you are stacking items up on a backstack so it's expected that there will be at least a little bit of a memory footprint but you can minimize the footprint by cleaning up resources when the fragment is out of view with the above technique.

The other suggestion is to get really good at understanding the output of the memory analyzer tool (MAT) and memory analysis in general. Here is a good starting point. It is really easy to leak memory in Android so it's a necessity in my opinion to get familiar with the concept and how memory can get away from you. It's possible that your issues are due to you not releasing resources when the fragment goes out of view as well as a memory leak of some kind so if you go the route of using setUserVisibleHint to trigger cleanup of your resources and you still see a high-volume of memory being used then a memory leak could be the culprit so make sure to rule them both out.



Related Topics



Leave a reply



Submit