PrefaceIn app development, images are indispensable. If the various icon image resources are not properly processed and used, the app performance will be seriously degraded, affecting the user experience. The most intuitive feeling is lag, the phone heats up, and sometimes OOM. So today we will analyze OOM and memory optimization summary; 1. What is OOM?
2. Types of OOM1. JVM memory model:According to the JVM specification, the JAVA virtual machine manages the following memory areas at runtime:
2. The most common OOM situations are the following three:
3. Why does OOM occur?Each process or each virtual machine of the Android system app has a maximum memory limit. If the memory resources requested exceed this limit, the system will throw an OOM error; It has little to do with the remaining memory of the entire device. For example, the virtual machine of the earlier Android system has a maximum memory of 16M. When an app is started, the virtual machine keeps requesting memory resources to load images. When the memory limit is exceeded, OOM occurs. Why is there no memory? There are two reasons: 1. Too little allocation: For example, the available memory of the virtual machine itself (usually specified by VM parameters at startup) is too small; 2. The application uses too much memory and does not release it after use, which is a waste, causing memory leaks or memory overflows;
In the days before automatic garbage collection, such as in C and C++, we had to be responsible for the memory allocation and release operations ourselves. If we allocated memory and forgot to release it after use, such as new but no delete in C++, then memory leaks may occur. Occasional memory leaks may not cause problems, but a large number of memory leaks may cause memory overflows; In the Java language, due to the existence of an automatic garbage collection mechanism, we generally do not need to actively release the memory occupied by unused objects, that is, in theory, there will be no "memory leaks". However, if the coding is improper, for example, a reference to an object is placed in a global Map, although the method ends, the garbage collector will recycle the memory based on the object's reference status, resulting in the object not being recycled in time. If this situation occurs more often, it will lead to memory overflow, such as the caching mechanism often used in the system. Memory leaks in Java are different from forgetting to delete in C++, which are often leaks due to logical reasons. 4. How to avoid OOM and optimize memory1. Reduce the memory usage of objectsThe first step to avoid OOM is to minimize the size of memory occupied by newly allocated objects and try to use lighter objects. 1) Use a lighter data structure We can consider using ArrayMap/SparseArray instead of traditional data structures such as HashMap. The brief working principle of HashMap shows that in most cases, it is inefficient and takes up more memory compared to the ArrayMap container written specifically for Android's mobile operating system. The usual HashMap implementation consumes more memory because it requires an additional instance object to record the Mapping operation. In addition, SparseArray is more efficient because it avoids autoboxing of keys and values and avoids unboxing after boxing. 2) Avoid using Enum in Android Enumerations typically require twice as much memory as static constants. You should strictly avoid using enumerations on Android. So please avoid using enumerations in Android. 3) Reduce the memory usage of Bitmap objects Bitmap is a big fat guy that easily consumes memory. Reducing the memory usage of the created Bitmap is a top priority. Generally speaking, there are two measures: inSampleSize: Scaling ratio. Before loading the image into memory, we need to calculate a suitable scaling ratio to avoid loading unnecessary large images. decode format: Decoding format, select ARGB_8888/RBG_565/ARGB_4444/ALPHA_8, there are big differences. 4) Use smaller images When it comes to resource images, we need to pay special attention to whether there is space for compression of this image and whether a smaller image can be used. Trying to use smaller images can not only reduce memory usage, but also avoid a large number of InflationExceptions. If a large image is directly referenced by an XML file, it is very likely that an InflationException will occur when the view is initialized due to insufficient memory. The root cause of this problem is actually OOM. 2. Reuse of memory objects
3. Avoid object memory leaksMemory object leakage will cause some unused objects to not be released in time, which will occupy valuable memory space and easily lead to insufficient free space when memory is needed later, resulting in OOM. Obviously, this also makes the available space in the memory area of each generation level smaller, making GC more likely to be triggered, memory jitter is likely to occur, and thus cause performance problems. 1) Pay attention to Activity leakage
2) Consider using Application Context instead of Activity Context For most situations where it is not necessary to use Activity Context (Dialog's Context must be Activity Context), we can consider using Application Context instead of Activity Context to avoid inadvertent Activity leakage; 3) Pay attention to the timely recycling of temporary Bitmap objects
4) Note the deregistration of the listener There are many listeners in Android programs that need to be registered and unregistered. We need to make sure to unregister those listeners in a timely manner when appropriate. If you manually add a listener, you need to remember to remove the listener in a timely manner. 5) Watch out for object leaks in cache containers Sometimes, we put some objects into the cache container to improve the reusability of objects. However, if these objects are not cleared from the container in time, it may also cause memory leaks. For example, for the 2.3 system, if a drawable is added to the cache container, it is easy to cause activity leakage due to the strong application of drawable and View. Starting from 4.0, this problem does not exist. To solve this problem, it is necessary to specially encapsulate the cache drawable on the 2.3 system, handle the problem of reference unbinding, and avoid leakage. 6) Pay attention to WebView leaks WebView in Android has a big compatibility problem. Not only does the difference in Android system version have a big difference in WebView, but also there are big differences in WebView in ROM shipped by different manufacturers. More seriously, the standard WebView has a memory leak problem, please see here. Therefore, the usual way to solve this problem is to start another process for WebView, communicate with the main process through AIDL, and the process where WebView is located can choose the appropriate time to destroy it according to business needs, so as to achieve complete release of memory. 7) Pay attention to whether the Cursor object is closed in time In the program, we often query the database, but there are often cases where the Cursor is not closed in time after being used accidentally. If these Cursor leaks occur repeatedly, they will have a great negative impact on memory management. We need to remember to close the Cursor object in time. 4. Optimize memory usage strategy1) Use large heap with caution
2) Consider the device memory threshold and other factors to design an appropriate cache size When designing the Bitmap LRU cache for ListView or GridView, the following points need to be considered:
3) onLowMemory() and onTrimMemory() Android users can quickly switch between different applications at will. In order to allow background applications to switch to foreground quickly, each background application will occupy a certain amount of memory. The Android system will decide to reclaim part of the background application memory based on the current system memory usage. If the background application is directly restored to forground from the suspended state, a faster recovery experience can be obtained. If the background application is restored from the Kill state, it will be a little slow in comparison.
When your app is running in the foreground, you may receive one of the following values returned from onTrimMemory():
When the app process is cached in the background, you may receive one of the following values returned from onTrimMemory():
Because the onTrimMemory() callback was added in API 14, for older versions, you can use the onLowMemory callback for compatibility. onLowMemory is equivalent to TRIM_MEMORY_COMPLETE. Please note: When the system starts to remove processes from the LRU cache, although it first performs operations in the order of LRU, it also considers the memory usage of the processes and other factors. The processes with less memory usage are more likely to be kept. 4) Resource files need to be stored in a suitable folder We know that images in hdpi/xhdpi/xxhdpi and other folders with different dpi will be scaled on different devices. For example, if we only put a 100x100 image in the hdpi directory, then according to the conversion relationship, the image will be stretched to 200x200 when referenced by an xxhdpi phone. It should be noted that in this case, the memory usage will increase significantly. For images that you do not want to be stretched, you need to put them in the assets or nodpi directory. 5)Try to catch some large memory allocation operations In some cases, we need to evaluate the code that may cause OOM in advance, and add a catch mechanism for the code that may cause OOM. We can consider trying a downgraded memory allocation operation in the catch. For example, when decoding a bitmap, if OOM is caught, we can try to double the sampling ratio and try decoding again. 6) Use static objects with caution Because the life cycle of static is too long and consistent with the application process, improper use is likely to cause object leakage. Static objects should be used with caution in Android. 7) Pay special attention to unreasonable holdings in singleton objects Although the singleton pattern is simple and practical and provides a lot of convenience, because the life cycle of the singleton is consistent with the application, improper use can easily lead to leakage of held objects. 8) Treasure Services Resources If your application needs to use a service in the background, the service should be stopped unless it is triggered and performs a task. Also, be aware of memory leaks caused by failure to stop the service after the service completes its task. When you start a service, the system tends to keep the process where the service is located in order to keep the service. This makes the process expensive to run 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 efficiency of switching between applications and may even cause unstable system memory usage, making it impossible to continue to maintain all currently running services. It is recommended to use IntentService, which will end itself as soon as possible after processing the task assigned to it. For more information, please read Running in a Background Service. 9) Optimize layout hierarchy and reduce memory consumption The flatter the view layout is, the less memory it takes up and the higher the efficiency. We need to try to ensure that the layout is flat enough. When the system-provided View cannot achieve a flat enough layout, consider using a custom View to achieve the goal. 10) Use "abstract" programming with caution Many times, developers use abstract classes as a "good programming practice" because abstraction can improve the flexibility and maintainability of the code. However, abstractions can cause a significant additional memory overhead: they require the same amount of code for execution, and that code will be mapped into memory, so if your abstraction does not significantly improve efficiency, you should try to avoid them. 11) Serialize data using nano protobufs Protocol buffers are designed by Google for serializing structured data. They are language-independent, platform-independent, and highly extensible. They are similar to XML, but are lighter, faster, and simpler than XML. If you need to serialize and protocolize your data, it is recommended to use nano protobufs. For more details, please refer to the "Nano version" section of the protobuf readme. 12) Use dependency injection frameworks with caution Those injection frameworks will perform many initialization operations by scanning your code, which will cause your code to require a lot of memory space to map the code, and the mapped pages will be retained in memory for a long time. Unless it is really necessary, it is recommended to use this technology with caution; 13) Use multi-process with caution
14) Use ProGuard to remove unnecessary code ProGuard can compress, optimize and obfuscate code by removing unnecessary code, renaming classes, fields and methods, etc. Using ProGuard can make your code more compact, which can reduce the memory space required for mapping code. 15) Use third-party libraries with caution Many open source library codes are not written for mobile network environments, 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. SummarizeMemory optimization does not mean that the less memory the program occupies, the better. If you frequently trigger GC operations in order to maintain a lower memory usage, it will lead to a decline in the overall application performance to a certain extent. Here we need to make comprehensive considerations and make certain trade-offs. Android memory optimization involves a lot of knowledge: the details of memory management, the working principle of garbage collection, how to find memory leaks, etc. OOM is a prominent point in memory optimization. Minimizing the probability of OOM is of great significance to memory optimization. |
<<: Why SwiftUI’s modifier order matters
>>: Your Phone app on Windows is coming to more Android smartphones
While the focus of Apple's event last Thursda...
This article will introduce in detail the specifi...
At the end of last month, a South Korean research...
Recently I heard someone say that the core keywor...
As we enter 2022, the epidemic, which had been do...
Produced by: Science Popularization China Author:...
Holidays have always been important marketing nod...
There are many tasks that operations are responsi...
Leather jacket live room speech. Welcome friends,...
Review expert: Ran Hao, a well-known popular scie...
Since the price of Xiaomi Mi Band was announced a...
[[133057]] Google Search alone and even Google An...
More and more online celebrity stores are breakin...
[[348746]] Today, the Ministry of Industry and In...
The battery pack is the core component of electri...