1. Memory Leak Memory leak: For Java, a newly created Object placed on the Heap cannot be recycled by GC (there are objects in the memory that cannot be recycled); when a memory leak occurs, the main manifestation is memory jitter, and the available memory gradually decreases. 1.1 Memory Monitor The Memory Monitor that comes with AndroidStudio can easily observe the allocation of heap memory, and can roughly observe whether there is any memory leak. Frequent memory jitters may indicate memory leaks A: initiate GC to manually trigger the GC operation; B: Dump Java Heap obtains the current stack information and generates a .hprof file, which AndroidStudip will automatically open with HeapViewer; it is generally used to detect memory leaks after operation; C: Start Allocation Tracking Memory allocation tracking tool, used to track memory allocation usage over a period of time, to know which objects are allocated space after a series of operations. Generally used to track memory allocation after a certain operation, and adjust related method calls to optimize app performance and memory usage; D: remaining available memory; E: Memory already used. Click Dump Java Heap in Memory Monitor to generate a .hprof file, which AndroidStudio will automatically open with HeapViewer. Hprof Viewer opens .hprof files Left panel description:
Right panel description:
It can be seen here that there are 15 sample objects in MainActivity, and it is suspected that there is a problem here. 1.2 MAT The above is just a rough indication of whether there is a problem, but to know where the problem lies, you need to use MAT. Convert the generated .hprof file and then open it with MAT; Format conversion command: hprof-conv Original file path Converted file path MAT open .hprof Note the following actions:
These two functions are generally used the most. Retained Heap represents the total memory occupied by this object and other references it holds (including direct and indirect)
Notice: There is a circle in the lower left corner of the icon in front of this$0, which means that this reference can be referenced by GC Roots. Since MainActivity$LeakClass can be accessed by GC Roots, it cannot be recycled, and thus other references it holds cannot be recycled, including MainActivity and other resources contained in MainActivity. At this point we have found the cause of the memory leak.
The specific cause of the leak can also be found by using the above Histogram operation method, which will not be repeated here. Note: The circle in front of each object icon does not necessarily mean that it is the cause of the memory leak. Some objects need to survive in the memory and need to be treated differently. 1.3 LeakCanary LeakCanary is a memory leak detection library produced by Square. Once integrated into the App, you don't need to worry about it. After a memory leak occurs, Toast, notification bar pop-up, etc. will be displayed to indicate the reference path of the leak, and the current stack information can be captured for detailed analysis. 2. Out Of Memory 2.1 Android OOM Each process in the Android system has a maximum memory limit. If the requested memory resources exceed this limit, the system will throw an OOM error.
Memory overflow is the final result of a program running to a certain stage. The direct reason is that the remaining memory cannot meet the memory application. However, let's analyze the indirect reasons why there is no memory:
2.2 Avoid Android OOM In addition to avoiding memory leaks, according to "Manage Your App's Memory", we can monitor the state of the memory, override this method in the Activity, and handle it differently according to different cases:
TRIM_MEMORY_RUNNING_MODERATE: Your app is running and is not listed as killable. However, the device is running in a low memory state and the system begins to trigger the mechanism of killing processes in the LRU cache. TRIM_MEMORY_RUNNING_LOW: Your app is running and is not listed as killable. However, the device is running in a low memory state and you should release unused resources to improve system performance. TRIM_MEMORY_RUNNING_CRITICAL: Your app is still running, but the system has killed most of the processes in the LRU Cache, so you should release all non-essential resources immediately. If the system cannot reclaim enough RAM, the system will clear all processes in the LRU cache and start killing those processes that were previously considered not to be killed, such as the process that contains a running Service. When the app process is cached in the background, you may receive one of the following values returned from onTrimMemory(): TRIM_MEMORY_BACKGROUND: The system is running low on memory and your process is in the least likely position to be killed in the LRU cache. Although your application process is not in high risk of being killed, the system may have started killing other processes in the LRU cache. You should release resources that are easily recoverable so that your process can be preserved and can be quickly recovered when the user returns to your application. TRIM_MEMORY_MODERATE: The system is running low on memory and your process is close to the middle of the LRU list. If the system starts to become more memory-constrained, your process may be killed. TRIM_MEMORY_COMPLETE: The system is running low on memory and your process is in the LRU list of processes most likely to be killed. You should release any resources that do not prevent your application from recovering. 3. Memory Churn Memory Churn: A large number of objects are created and released immediately within a short period of time. The instantaneous generation of a large number of objects will seriously occupy the memory area of the Young Generation. When the threshold is reached and there is not enough remaining space, GC will be triggered. The more time the system spends on GC, the less time it has to draw the interface or process streaming audio. Even if each allocated object takes up very little memory, their accumulation will increase the pressure on the Heap, thereby triggering more other types of GC. This operation may affect the frame rate and make users perceive performance issues. Drop Frame Occur Common situations that may cause memory thrashing:
For example, some of the pull-to-refresh control implementations used before create multiple temporary large objects such as Bitmap in onDraw, which will cause memory jitter. 4. Bitmap Bitmap processing is also a difficulty in Android. Of course, this difficulty can be avoided by using a third-party framework.
I will write a special article to introduce Bitmap later. You can refer to "Handling Bitmaps" here. 5. Program Advice 5.1 Use Services sparingly One of the worst mistakes in memory management is leaving the Service running all the time. When using a service in the background, it should be stopped unless it needs to be triggered to perform a task. Also, it should be stopped after the service is done to avoid memory leaks. The system tends to keep the process where the Service is located, which makes the process run very expensive, because the system has no way to free up the RAM space occupied by the Service for other components, and the Service cannot be Paged out. This reduces the number of processes that the system can store in the LRU cache, which affects the switching efficiency between applications and even causes unstable system memory usage, making it impossible to continue to maintain all currently running services. It is recommended to use JobScheduler and avoid using persistent Services. It is also recommended to use IntentService, which will end itself as soon as possible after processing the task assigned to it. 5.2 Using Optimized Collections The Android API provides some optimized data collection tool classes, such as SparseArray, SparseBooleanArray, and LongSparseArray, which can make our programs more efficient. The HashMap tool class provided in the traditional Java API is relatively inefficient because it needs to provide an object entry for each key-value pair, while SparseArray avoids the time of converting basic data types into object data types. 5.3 Be cautious with abstraction orientation Developers often use abstraction as a good programming practice because it can improve the flexibility and maintainability of the code. However, abstraction can lead to a significant overhead: abstraction requires additional code (which will not be executed) and is also mapped into memory, which takes more time and memory space. Therefore, if abstraction does not have a significant benefit to your code, you should avoid using it. For example: using enumerations usually consumes more than twice the memory than using static constants. In Android development, we should avoid using enumerations as much as possible. 5.4 Serializing Data Using Nano Protobufs Protocol buffers is a language-independent, platform-independent, and highly extensible data description language designed by Google for serialized data. It is similar to XML, but is lighter, faster, and simpler. If you use protobufs to serialize and deserialize data, it is recommended to use nano protobufs on the client side, because ordinary protobufs will generate redundant code, which will reduce available memory, increase the size of the Apk, and slow down the running speed. 5.5 Avoiding Memory Thrashing Garbage collection usually does not affect the performance of the application, but multiple garbage collections in a short period of time will consume the time of interface drawing. The more time the system spends on GC, the less time it has to draw the interface or process streaming audio. Usually memory jitter will cause multiple GCs. In practice, memory jitter means that temporary objects are allocated over a period of time. For example, multiple temporary objects are allocated in a For loop, or Paint and Bitmap objects are created in the onDraw() method. The application generates a large number of objects, which will quickly exhaust the available memory of the young generation and cause GC to occur. Use the tools in Analyze your RAM usage to find places in your code where memory is thrashing. Consider moving operations out of inner loops, or into factory-based allocation structures. 5.6 Remove memory-consuming libraries and reduce the size of the Apk Check the size of the APK, including third-party libraries and embedded resources, which will affect the memory consumed by the application. By reducing redundant, non-essential or large components, libraries, images, resources, animations, etc., you can improve the memory consumption of the application. 5.7 Dependency Injection Using Dagger 2 If you plan to use a dependency injection framework in your application, consider using Dagger 2. Dagger does not use reflection to scan your application's code. Dagger's compile-time annotation technology means that it does not require unnecessary runtime costs. Other dependency injection frameworks that use reflection usually initialize the process by scanning the code. This process can require significantly more CPU cycles and RAM, and can cause noticeable lags when your application starts. Note: The previous document does not recommend the use of dependency injection frameworks because the implementation principle is to use reflection. After evolving to compile-time annotations, there is no longer any impact from reflection. 5.8 Use third-party libraries with caution Many open source library codes are not written for mobile devices, and may not be suitable for use on mobile devices. Even libraries designed for Android require special caution, especially when you don't know what the imported library does specifically. For example, one library uses nano protobufs, while the other uses micro protobufs. In this way, there are two protobuf implementations in your application. Similar conflicts may also occur in modules such as output logs, loading images, caching, etc. In addition, do not import the entire library for one or two functions. If there is no suitable library that matches your needs, you should consider implementing it yourself instead of importing a large and comprehensive solution. 6. Other 6.1 Use LargeHeap properties with caution You can declare a larger heap size for your application by adding the attribute largeHeap=true to the application tag in the manifest (you can get this larger heap size threshold through getLargeMemoryClass()). However, the original intention of declaring a larger heap threshold is for a small number of applications that consume a lot of RAM (such as a large image editing application). Don't easily request a large heap size just because you need to use more memory. Only use a large heap when you clearly know where a large amount of memory is used and why this memory must be retained. Using additional memory space will affect the overall user experience of the system and will make each GC run longer. The performance of the system will be greatly reduced when switching tasks. In addition, a large heap does not necessarily get a larger heap. On some machines with strict restrictions, the size of the large heap is the same as the normal heap size. 6.2 Use multiprocessing with caution Multi-process is indeed an advanced technique that can help us save and manage memory. If you want to use it, you must use it with caution, because most applications should not be run in multiple processes. Once used improperly, it will even increase additional memory instead of helping us save memory; at the same time, you need to know the disadvantages of multi-process. This technique is more suitable for scenarios where you need to complete an independent task in the background, which can be completely distinguished from the foreground function. Here is a scenario that is more suitable for using multi-process techniques. For example, we are making a music player software, in which the function of playing music should be an independent function. It does not need to have any relationship with the UI. Even if the software is closed, it should be able to play music normally. If we only use one process at this time, then even if the user closes the software and the music playback is completely controlled by the Service, the system will still retain a lot of UI memory. In this scenario, it is very suitable to use two processes, one for UI display and the other for continuous music playback in the background. 6.3 Possible problems with the implementation: For example, the Bitmap of the startup page splash screen should be released after the display is completed. Some implementations seem to work fine but may actually have an impact on memory usage. When I used the Heap Viewer to view the Bitmap object, I found a picture that only needed to be downloaded and should not be loaded. Use HeapViewer to view Bitmap directly Images that should not be loaded appear in memory By checking the code, I found that the problem lies in: the image is downloaded here as a use image for another module, but the download method is to use the image loader to load the Bitmap and then save it locally; and the Bitmap object is not released after saving. Similarly, after the home page splash screen is displayed, the Bitmap object should be released in time. 6.4 Using try catch to capture Perform try catch on high-risk OOM code blocks, such as displaying high-definition images, and load non-HD images in the catch block and perform corresponding memory recycling. Note that OOM is OutOfMemoryError and cannot be captured using Exception. 7. Summary Memory optimization routine: (1) Solve all memory leaks
(2) Avoid memory jitter
(3) Use of Bitmap
(4) Use of Library
|
>>: Android Gradle from understanding to practice
There is no doubt that the topic of mini programs...
Compiled by: Gong Zixin Can you really make up fo...
What is content marketing ? Why do content market...
1. A land transfer announcement was posted on the...
What is the logic behind PUSH? To sum it up, it c...
This article was reviewed by Liu Yong, space phys...
The larger the parameters of an artificial intell...
As the threshold for APP development is lowered, ...
Alien planetary system has a Jupiter world 99 tim...
• Introduction• The straw that broke the camel...
Most of the articles on the market about informat...
Although the service life of the International Sp...
Target: A national wedding photography chain clie...
For today’s car companies, if they can’t get high...
Someone left me a message before, asking if I cou...