In Android application development, memory management and garbage collection (GC) are crucial to application performance and stability. Understanding the GC mechanism helps us write more efficient code and avoid memory leaks and memory overflows. This article will delve into how the Android GC mechanism works. If you are interested in memory management, you can also read my article Android Memory Optimization Practice .
Contents
1. Memory allocation
Android applications run on the Dalvik virtual machine (before Android 4.4) or the ART virtual machine (Android 4.4 and later). The virtual machine is responsible for allocating and managing memory for applications. When an application needs to allocate memory, the virtual machine allocates a space in the heap memory. Heap memory is a memory area shared by all application threads and is used to store objects and data.
As the application runs, new objects will continue to be generated in the heap memory. When objects are no longer used, the memory they occupy needs to be reclaimed so that space can be allocated for new objects. This is the main task of garbage collection.
2. Garbage collection trigger conditions
Garbage collection can be triggered by the following conditions:
- Insufficient heap memory: When an application attempts to allocate memory, but the heap memory is insufficient to meet the demand, the GC will be triggered to reclaim the memory occupied by objects that are no longer used.
- Explicit calls: Applications can
System.gc()
explicitly trigger GC by calling. However, this approach is generally not recommended because it may cause GC to be too frequent, affecting application performance. - Periodic execution: The virtual machine may perform GC periodically to keep the heap memory clean. In this case, the triggering timing of GC is determined by the virtual machine.
3. GC algorithm
The Android operating system uses the Dalvik virtual machine or ART (Android RunTime) to execute application code. These two virtual machines differ in their garbage collection (GC) algorithms.
3.1 GC algorithm of Dalvik virtual machine
The Dalvik virtual machine mainly uses two GC algorithms: Mark-Sweep and Mark-Compact.
- Mark-and-sweep algorithm:
- In the marking phase, starting from GC Roots ( the root node of garbage collection, such as global variables, local variables in the stack, etc. ), all reference relationships are traversed and all accessible objects are marked as alive. This process can be accomplished through depth-first search (DFS) or breadth-first search (BFS).
- During the cleanup phase, the garbage collector will clear out all unmarked (that is, unreachable) objects and reclaim the memory they occupy.
- The main problems with this algorithm are memory fragmentation and the need to stop the application during the mark and clear phases (Stop-The-World).
- Mark-compression algorithm: In order to solve the problem of memory fragmentation, the Dalvik virtual machine will use the mark-compression algorithm when memory is tight. This algorithm adds a compression stage based on mark-sweep to move all surviving objects to one end of the memory, thereby reducing memory fragmentation.
3.2 ART’s GC algorithm
ART has made many optimizations based on Dalvik, including the garbage collection algorithm. ART mainly uses two GC algorithms: Generational Collection and Concurrent Mark-Sweep (CMS).
- Generational collection: This algorithm divides memory into several regions (generations), placing objects into different generations based on their lifetime. Usually, newly created objects will be placed in the new generation, and objects that have survived multiple GCs will be placed in the old generation. Generational collection can reduce GC overhead, because most objects are short-lived and only the new generation needs to be GCed. The main advantage of the generational collection algorithm is that it can reduce the number of global GCs, thereby improving application performance. The Android virtual machine divides the heap memory into the following generations:
- Young Generation: Newly created objects are allocated in the young generation. The GC frequency of the young generation is higher, but the recycling speed is faster because most newly created objects have a short life cycle.
- Old Generation: Objects promoted from the young generation are allocated in the old generation. The GC frequency in the old generation is lower, but the recycling speed is slower because the objects in the old generation have a longer life cycle.
- Permanent Generation: used to store class metadata and static variables. The permanent generation has the lowest GC frequency, but the slowest recycling speed.
- Concurrent mark-sweep: This algorithm executes concurrently (simultaneously) during the mark and sweep phases, reducing application pause time. This is an important improvement for the user experience because users will not feel the application is stuck due to GC.
In general, the GC algorithm of the Android virtual machine is to minimize the impact of GC on application performance and user experience while ensuring memory usage efficiency.
4. Optimize GC performance
In order to reduce the impact of garbage collection on application performance, we can take the following measures:
- Reduce object creation: Avoid unnecessary object creation and try to reuse existing objects. For example, you can use an object pool to reuse objects, or use static factory methods to create objects.
- Use weak references and soft references: For objects that do not need to be held for a long time, you can use weak references (WeakReference) or soft references (SoftReference) instead of strong references. This way, the garbage collector can reclaim these objects when needed, thus reducing the memory footprint.
- Avoid memory leaks: A memory leak occurs when an application fails to release memory occupied by objects that are no longer used. Memory leaks can cause heap memory to grow continuously, triggering frequent garbage collection. To avoid memory leaks, we need to ensure that resources (such as files, database connections, etc.) are closed properly and object references are dereferenced when they are no longer needed.
- Avoid using global static variables: Global static variables will extend the life cycle of the object, thereby increasing the burden on the GC. Try to use local variables and pass parameters to share objects.
- Optimize data structures: Using appropriate data structures and algorithms can reduce memory footprint and object creation. For example, a SparseArray can be used instead of a HashMap to store sparse key-value pairs.5. Monitor GC time consumption
Monitoring GC (Garbage Collection) time consumption is an important performance optimization method. The GC process will suspend the running of the application. Therefore, frequent GC will affect the startup speed and response speed of the application. Here are some commonly used monitoring methods:
- Use the Profiler tool of Android Studio: The Profiler tool that comes with Android Studio can help us monitor the running status of the application, including the time-consuming situation of GC. We can see the detailed information of GC in the Memory tab of the Profiler tool, including the number of GCs, the time taken for each GC, and the memory usage after each GC.
- Use adb command: We can use adb command to obtain the GC information of the application. For example, we can use
adb shell dumpsys meminfo <package_name>
the command to obtain the memory usage of the application, including the number of GC times and the total time taken. We can also use the adb logcat -s GC command to obtain detailed logs of GC. Debug.startMethodTracing()
Using code: We can use the and method in the codeDebug.stopMethodTracing()
to turn on and off method tracking, and then useDebug.getNativeHeapAllocatedSize()
the method to get the allocated memory size. By comparingDebug.getNativeHeapAllocatedSize()
the results of two method calls, we can estimate the GC time.
The above method can help us monitor the GC time consumption in Android. Through monitoring, we can find out the reasons for frequent GC, such as memory leaks, over-allocation, etc., and make corresponding optimizations to improve the startup speed and response speed of the application.
6. Summary
In short, understanding the Android garbage collection mechanism helps us write more efficient code and improve application performance. By reducing object creation, using weak and soft references, avoiding memory leaks, and optimizing data structures, we can reduce the frequency and cost of garbage collection, thereby improving application responsiveness and stability.