(Click the public account above to quickly follow)
Source: BlackSwift
http://www.jianshu.com/p/8c6cf3d7a98a
If you have good articles to submit, please click → here to learn more
Android system runs on the Java virtual machine, and as an embedded device, memory is often very limited. Understanding the garbage collection mechanism of Android can effectively prevent memory leak issues or OOM problems. This article serves as an introductory piece, discussing the principles of garbage collection and memory leaks in a simple manner, without delving into the underlying mechanisms of the Dalvik virtual machine or native-level issues.
1. Basics
Before analyzing garbage collection, we need to review the basics of Java and discrete mathematics.
-
Instantiation: An object is an instance of a class, and the process of creating an object is called class instantiation. An object is created using a class as a template. For example, Car car = new Car(); creates an instance of Car (Create new class instance of Car).
-
Reference: The instantiation of certain objects requires other object instances. For example, the instantiation of ImageView requires a Context object, which means that ImageView holds a reference to Context (ImageView holds a reference to Context).
-
Directed Graph: A graph in which each edge is marked with a directed line segment is called a directed graph. The garbage collection in Java uses a directed graph approach for memory management, where the direction of the arrow indicates the reference relationship. For example, B ← A means B needs A, B references A.
-
Reachable: In a directed graph D={S,R}, for Si, Sj belonging to S, if there exists any path from Si to Sj, then Si is said to be reachable to Sj. In other words, when the arrow in B ← A is broken, it is called unreachable, meaning A is no longer reachable to B.
-
Comparison between Shallow Heap and Retained Heap
-
Shallow Heap represents the memory consumed by the current object.
-
Retained Heap represents the total memory consumed by the current object plus all the memory it references.
Google I/O 2011: Memory management for Android Apps
The orange Object in the image above is the starting point of the directed graph, its Shallow Heap is 100, while its Retained Heap is 100 + 300 = 400.
2. What is Garbage Collection
The Java GC (Garbage Collection) mechanism is one of the main differences between Java and C++/C. As a Java developer, you generally do not need to write memory recovery and garbage cleaning code specifically, and you do not need to be as cautious about memory leaks and overflow issues as C programmers. This is because there is automatic memory management and garbage cleaning mechanism in the Java virtual machine. In summary, this mechanism marks the memory in the virtual machine and determines which memory needs to be reclaimed. Based on certain reclamation strategies, it automatically reclaims memory, ensuring that the memory space in the virtual machine is never stopped (Never Stop), preventing memory leaks and overflow issues.
3. When is Garbage Collection Needed
For GC, when a programmer creates an object, GC starts monitoring the address, size, and usage of that object. Typically, GC uses a directed graph approach to record and manage all objects in the heap, determining which objects are “reachable” and which are “unreachable”. When an object is unreachable, meaning it is no longer referenced, it will be garbage collected.
There are many documents online that introduce the relationship of reachability. For example, in the sixth line, when o2 changes its reference, Obj2 no longer references main, meaning they are unreachable, and Obj2 may be collected in the next GC.
developerWorks Java technology
4. What is a Memory Leak
A memory leak occurs when you no longer need a certain instance, but the object is still referenced, preventing it from being garbage collected (Prevent from being garbage collected). This situation is called a memory leak (Memory Leak).
Below is an example of a memory leak using the article How to Leak a Context: Handlers & Inner Classes.
Look at the following code.
public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } }
After you finish this code, the IDE should remind you.
In Android, Handler classes should be static or leaks might occur.
How does it leak?
-
When you start an application, it automatically creates a Looper object in the main thread to handle messages in the Handler. Looper implements a simple message queue, processing Message objects one by one in a loop. Most Application framework events (such as Activity lifecycle calls, button clicks, etc.) are in Messages and processed one by one in the Looper’s message queue. Note that Looper exists throughout the application’s lifecycle.
-
When you create a handler object, it will be assigned to the Looper’s message queue. Messages sent to the message queue will hold a reference to the Handler because when the message queue processes this message, it needs to use [Handler#handleMessage(Message)](http://developer.android.com/reference/android/os/Handler.html#handleMessage(android.os.Message)). (That is, as long as this Message is not processed, the Handler is always referenced in the queue)
-
In Java, non-static inner classes and anonymous classes hold strong references to their outer classes, except for static inner classes.
Reference relationship
Now, let’s try running the following code.
public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mLeakyHandler.postDelayed(new Runnable() { @Override public void run() { /* ... */ } }, 1000 * 60 * 10); // Go back to the previous Activity. finish(); } }
This program is simple. We can imagine it starts and then closes instantly, but did it really close?
Anyone with a little knowledge can see that it sends a Message that will run after ten minutes, meaning the Message will be held for reference for 10 minutes, causing at least 10 minutes of memory leak.
The correct code is as follows.
public class SampleActivity extends Activity { /** * Instances of static inner classes do not hold an implicit * reference to their outer class. */ private static class MyHandler extends Handler { private final WeakReference<SampleActivity> mActivity; public MyHandler(SampleActivity activity) { mActivity = new WeakReference<SampleActivity>(activity); } @Override public void handleMessage(Message msg) { SampleActivity activity = mActivity.get(); if (activity != null) { // ... } } } private final MyHandler mHandler = new MyHandler(this); /** * Instances of anonymous classes do not hold an implicit * reference to their outer class when they are "static". */ private static final Runnable sRunnable = new Runnable() { @Override public void run() { /* ... */ } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mHandler.postDelayed(sRunnable, 1000 * 60 * 10); // Go back to the previous Activity. finish(); } }
Conclusion
-
GC determines whether an object instance is useful based on whether it is reachable in a directed graph.
-
If an instance is no longer needed but still referenced, this situation is called a memory leak.
-
Anonymous classes/non-static inner classes will hold references to their containing Activity, so be careful that their lifecycle does not exceed that of the Activity, or use static inner classes.
-
Be good at manually controlling the lifecycle of other classes in the Activity lifecycle (e.g., onPause).
Finally, let’s add a note on iOS. In the new versions of OC and Swift, iOS has introduced a new memory management system called ARC (automatic reference counting), where the compiler automatically adds code to release memory at compile time.
References
-
http://www.jianshu.com/p/22e73e80e950
-
http://www.ibm.com/developerworks/cn/java/l-JavaMemoryLeak/
-
http://stackoverflow.com/a/70358/4016014
-
http://blog.csdn.net/luoshengyang/article/details/8852432
-
http://developer.android.com/training/articles/perf-tips.html
-
https://techblog.badoo.com/blog/2014/08/28/android-handler-memory-leaks/
Did you gain anything from this article? Please share it with more people.
Follow “Android Development Essentials” to improve your Android development skills.