preface
In Android development, memory leak is a term I think everyone is familiar with, but it is estimated that few people really pay attention to this problem and solve it, because memory leak does not appear to have any impact on the app, in addition to the current mobile phone configuration and memory are very high, so for small and medium-sized apps, You probably don’t deal with it much and it’s barely noticeable, but as an Android developer, you must be as sick of it as I am, so just roll up your sleeves and get on with it
Memory jitter & Memory Leak & Memory Overflow (OOM)
Memory jitter
Meaning: A large number of objects are created and destroyed in a short period of time, which is accompanied by frequent GC.
-
View: You can use the Profile tool that comes with Android Studio.
-
Phenomenon: The memory image in the profile is like an ELECTROcardiogram, up and down, as shown below:
-
Common scenarios: Looping string concatenation, such as our project’s log printing, etc
-
Methods to prevent memory jitter:
- Avoid creating objects in loops and reuse what you can.
- Avoid creating objects in frequently called methods such as onDraw () in custom views.
- Obtain objects from the object pool where possible, such as Handler to obtain Message objects should be obtained using the obtain () method.
A memory leak
The heap memory that has been allocated dynamically in the program is not released or cannot be released for some reason, resulting in a waste of system memory. The long life cycle object holds strong references to the short life cycle object, which causes the short life cycle object to not be reclaimed!
-
View: Use the profile tool to check memory and repeatedly enter and exit an activity to see if the activity instance still exists. If the activity instance still exists, there is likely to be a memory leak.
-
Symptom: Repeatedly enter A and exit A for three times. Two instances of A exist. Here’s VideoPlayerActivity:
This means that our activity has not been destroyed, at least for now. Whether there will be a memory leak or not will need to be used with another tool.
- How to identify a memory leak:
- Use accessibility analysis
All chains of references are searched through a series of objects called “GC Roots” as starting points, and an object is proved to be unavailable when there is no chain of references to the GC Roots (i.e. the GC Roots are unreachable to the object). It will be recycled.
-
What is a GC Roots object? A static variable is a GC root object, which can be understood as an object with a long lifetime.
-
How to prevent memory leaks:
-
Holding references to objects indirectly using soft references, weak references.
-
Soft references:
Define objects that are useful but not necessary. Objects associated with soft references are not directly collected by GC, but are triggered by GC to collect them before the system runs out of memory.
- Weak references:
Define non-required objects as well. Objects associated with weak references are directly reclaimed during GC execution.
- Common scenarios for memory leaks:
- When using a collection, such as adding a listener, we must remove it manually.
- When using static member variables/single-interest objects, holding a reference to a short-life object (Activity) causes the short-life object to be unable to be released.
- File I/O is performed without close (). In finally{};
- Android system bugs, third-party class libraries caused by memory leaks.
Out of memory
Out Of Memory (OOM) refers to an application system that has Memory that cannot be reclaimed or is using too much Memory. As a result, the program needs more Memory than the maximum available Memory. At this point, the program will not run, the system will prompt memory overflow, sometimes automatically shut down the software, restart the computer or software after the release of some memory and can run the software normally
- Frequent memory jitter or large memory leaks are likely to cause a memory overflow (OOM).
Garbage collector CMS in Android
The garbage collector used in Android is called CMS. Here is a brief introduction to its garbage collection algorithm.
- Cenozoic object
The new generation of objects is a copy algorithm, when the large objects may also directly into the old age.
- Old age object
In the old days, objects used the mark-clear algorithm, so frequent memory jitter will cause memory fragmentation. In the end, we may need to load a large object, and then OOM will be used.
Briefly introduce CMS garbage collection algorithm, if you are not familiar with the suggestion, please baidu JVM garbage collection mechanism related knowledge.
Actual memory leak
Configure the environment
- android studio
- eclipse memory analyzer (mat)
Download the mat
- Download address click me
Select the version to download and install.
- Configure the MAT environment. Because the hprof file format obtained directly from the Android profile is incompatible with the MAT format, you need to use the tools to convert it
Win environment configuration, please baidu, because I use the Mac so here only write the Mac configuration
- Open the terminal and enter echo $HOME
- Continue typing: touch.bash_profile
- Continue typing: open-e. bash_profile
- Export PATH=${PATH}:/Users/ user name/your SDK PATH /platform-tools
- Finally enter: source-bash_profile
- There is no more 6, it has been successfully configured.
Use profile to obtain the memory analysis file
Whatever the name is, what’s convenient
Open the terminal and convert files
Conversion format: hprof-conv before.hprof after.hprof
Here we type: hprof-conv memory-99. Hprof 66. Hprof can read it and convert our source file -99 to -66.
Note: you need to enter the file directory where -99 is located, otherwise an error will be reported that the file is not found
Open the mat tool and import our -66 file
When opened, you can see this interface
Click the option in the red box. This one is for memory leak analysis
Here are the objects generated during this time. Click on the red box to search directly for the object you want to analyze
Here’s our VideoPlayerActivity
Right mouse click
As you can see, this means that we exclude soft, weak, and virtual references, which do not cause memory leaks. We just need to see if there are any references after exclusion. If there are strong references, then there will be a memory leak.
Keep looking at our results:
After clicking, we find that there is data in the profile, which indicates that we have a memory leak. That is why we have exited the profile above, there are still three activities in the profile, and there are also three activity objects in the right side of the picture above.
Let’s expand it out and see where the memory leak is
As you can see, our Avtivity is held as the mContext variable by our custom CoverVideoPlayerView, which means that because our custom View cannot be collected by GC, the activity cannot be collected either.
So let’s go ahead and see why our custom view can’t be recycled, and you can see that this$0 means that we have a non-static inner class inside our custom view, and the non-static inner class by default holds a reference to the outer class, which is our mNetChangeListener object, so you’re familiar with that, It must be new an anonymous inner class,
Continue to see, this inner class is again referenced by NetInfoModeule, I lose, then continue to see, I don’t look at, you see
I’m gonna get a glass of water. You take your time
What? I’m home from drinking. You haven’t finished yet? Why don’t we watch it together,
Further up, you can see that NetInfoModeule is referenced by some xxxxxBroadcastReceiver. Isn’t that a broadcast? Guess, it must be another non-static inner class. Look up
Ahem, don’t look, it has nothing to do with us, it’s all about the system,
Through the above analysis, we should be clear about the cause of the leak,
Then comb through:
VideoPlayerActivity -> mContext -> CoverVideoPlayerView -> mNetChangeListener -> NetInfoModeule -> xxxxxBroadcastReceiver;
The reference chain is found, so we give the chain to the whole segment, so there will be no memory leak
What is it?
The easiest way: If you wrote all the bad code yourself, it’s easy
In the activity's onDestory () method, add, 1.CoverVideoPlayerView. 2. In the CoverVideoPlayerView method, add a method of cancel () with mContext = null mNetChangeListener = null; NetInfoModeule = null; And then unregister (), and we're done.Copy the code
Well, everything is as sweet as it looks, but the hard truth is that this is third-party library code, how do you change it? Next source change? Okay, it’s feasible, but what about multiple libraries? Do you want to play again? Also don’t change?
Well, let’s not change it, ok, it doesn’t seem to matter anyway, and our VideoPlayerActivity uses the “SingleTop” launch mode, but if you’re not on the playing page and the user clicks on it, exit and come back, exit and come back, the last dozen or so instances of the activity, With our model, viewModel, are all more than ten copies, are you sure you will not be taken out by the boss to worship heaven?
The interface is as follows:
So how do you change it? Tell me about it.
Of course you can change it, and that’s using Java reflection, which is to take the object and modify it,
Go straight to the code
/** * Use reflection to fix memory leak in gSY library */ public voidcancel() { mAudioManager.abandonAudioFocus(onAudioFocusChangeListener); Try {/ / get NetInfoModule mConnectivityBroadcastReceiver fields in the object. Field mConnectivityBroadcastReceiver = NetInfoModule.class .getDeclaredField("mConnectivityBroadcastReceiver"); // This field is called because it is a private fieldsetAccessible(true), otherwise an error mConnectivityBroadcastReceiver. SetAccessible (true); / / object according to the current mNetInfoModule mConnectivityBroadcastReceiver field value is null mConnectivityBroadcastReceiver. Set (mNetInfoModule, null); Field mNetChangeListener = NetInfoModule.class.getDeclaredField("mNetChangeListener");
mNetChangeListener.setAccessible(true);
mNetChangeListener.set(mNetInfoModule, null);
}
catch (NoSuchFieldException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
mAudioManager = null;
mContext = null;
}
Copy the code
All right, that’s it. Now let’s get a little bit of memory
Directly above:
Activiy is not strongly referenced by other objects, but as long as there is no strong reference relationship, GC can recycle it, and naturally you do not need to worry about memory leak.
But why does it still show that there are three activity objects?
So let’s rule out weak applications and see
See, there’s a FinalizeRefernce object here, so our activity is referenced by that FinalizeRefernce object, and we know that whenever an object is about to be collected by GC, it’s referenced by that FinalizeRefernce object, This is to let gc know that we don’t need this object anymore, you can recycle it,
So our activity shows two, but only the gc has not yet come and collection, there is no risk of memory leak.
The above example is a real example of my open source project, if you are interested in supporting Start,
The project address
-
Android-MvvmComponent-App
conclusion
The analysis of memory jitter with the profile tool is completely sufficient, of course, we do not detail how to use profile analysis to solve memory jitter, there is time to fill in the later. As for our memory leak, it is impossible to see whether there is a memory leak through profile, so we need to further analyze with the help of MAT tool.
Of course, there are also some third-party detection libraries, such as leakCannary tool and Tencent’s XXxDog, but I recommend using MAT for analysis. Mat is also very convenient to operate. Ok, that’s all for today, thank you!
Welcome to Darryrzhong for more.
A little red heart, please! Because your encouragement is the biggest motivation for my writing!
More exciting articles please pay attention
- Personal blog: Darryrzhong
- The Denver nuggets
- Jane’s book
- SegmentFault
- MoOCs