Background knowledge
By default, each app in Android runs in an independent process, and this independent process is the VM process incubated from Zygote. That is to say, each Android app will start a Java virtual machine when it is run.
And the system will allocate fixed memory space to it (mobile phone manufacturers will adjust it according to the configuration of the phone).
1. The memory space of Android VM
Android is a multi-task system. In order to ensure the operation of multi-tasks, Android sets a limit value for the Heap size that each App can use.
This value is the prop value set by the system, saved inSystem/
In the file. Generally, domestic mobile phone manufacturers will make modifications. Depending on the configuration of the mobile phone, you can open it directly to view and modify it.
Among them, there are three main related to virtual machine memory:
1 .
– After the app is started, the initial Heap size assigned to it by the system can increase as the app is used.
2 .
– By default, the maximum value of Heap that the App can use, exceeding this value will result in OOM.
3 .
– If the largeHeap property is configured in the App's manifest file, the maximum value of Heap that the App can use is set to this item.
<application android:largeHeap="true"> ... </application>
So for the same phone, it doesn't turn onlargeHeap
When the attribute is used and when the multi-process, the upper limit of the memory allocated by the virtual machine of each APP isheapgrowthlimit
。
1. View the memory API
Android provides an API in the ActivityManager class to get these attribute values when running, as follows:
// ActivityManager's getMemoryClass() gets the memory size under normal circumstances, that is, the value of heapgrowthlimit// ActivityManager's getLargeMemoryClass() can get the maximum memory size of largeHeap, that is, the heapsize fingerActivityManager activityManager = (ActivityManager)(Context.ACTIVITY_SERVICE); (); ();
2. Android VM memory allocation process
The specific source code of the virtual machine allocated memory can be viewed in the AOSP file:
/* Try as hard as possible to allocate some memory. */ static void *tryMalloc(size_t size) { void *ptr; //TODO: figure out better heuristics // There will be a lot of churn if someone allocates a bunch of // big objects in a row, and we hit the frag case each time. // A full GC for each. // Maybe we grow the heap in bigger leaps // Maybe we skip the GC if the size is large and we did one recently // (number of allocations ago) (watch for thread effects) // DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other // (or, at least, there are only 0-5 objects swept each time) ptr = dvmHeapSourceAlloc(size); if (ptr != NULL) { return ptr; } /* * The allocation failed. If the GC is running, block until it * completes and retry. */ if (->gcRunning) { /* * The GC is concurrently tracing the heap. Release the heap * lock, wait for the GC to complete, and retrying allocating. */ dvmWaitForConcurrentGcToComplete(); } else { /* * Try a foreground GC since a concurrent GC is not currently running. */ gcForMalloc(false); } ptr = dvmHeapSourceAlloc(size); if (ptr != NULL) { return ptr; } /* Even that didn't work; this is an exceptional state. * Try harder, growing the heap if necessary. */ ptr = dvmHeapSourceAllocAndGrow(size); if (ptr != NULL) { size_t newHeapSize; newHeapSize = dvmHeapSourceGetIdealFootprint(); //TODO: may want to grow a little bit more so that the amount of free // space is equal to the old free space + the utilization slop for // the new allocation. LOGI_HEAP("Grow heap (frag case) to " "%zu.%03zuMB for %zu-byte allocation", FRACTIONAL_MB(newHeapSize), size); return ptr; } /* Most allocations should have succeeded by now, so the heap * is really full, really fragmented, or the requested size is * really big. Do another GC, collecting SoftReferences this * time. The VM spec requires that all SoftReferences have * been collected and cleared before throwing an OOME. */ //TODO: wait for the finalizers from the previous GC to finish LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation", size); gcForMalloc(true); ptr = dvmHeapSourceAllocAndGrow(size); if (ptr != NULL) { return ptr; } //TODO: maybe wait for finalizers and try one last time LOGE_HEAP("Out of memory on a %zd-byte allocation.", size); //TODO: tell the HeapSource to dump its state dvmDumpThread(dvmThreadSelf(), false); return NULL; }
The specific process is as follows:
- Try to allocate, return if successful, and go to step 2 if failed
- Determine whether gc is performing garbage collection. If it is performing, wait for the recycling to be completed and try to allocate. If successful, return, and if failed, go to step 3
- Start gc yourself for garbage collection, here the parameter of gcForMalloc is false. So soft references will not be recycled. Try to allocate after recycling is completed. If it succeeds, it will return. If it fails, it will go to step 4
- Call dvmHeapSourceAllocAndGrow to try to allocate. This function will expand the size of the heap and fail to go to step 5.
- Entering the soft reference recycling stage, the parameter of gcForMalloc is ture, so soft references need to be recycled. Then call dvmHeapSourceAllocAndGrow and try to allocate, and if it fails, throw OOM
summary
So when OOM is generated, it must be in the java heap.Already memory + requested memory >= caused by heapgrowthlimit, will not change because of whether the phone is currently tight in physical memory - when the physical memory is very tight, the system will kill some low-priority processes through LowMemory Killer.
Correspondingly, OOM will also occur if the physical memory is very sufficient.
3. Suggested solutions for OOM emergence
When OOM appears on the APP, it is recommended to handle it from the following two directions:
1 . Troubleshoot memory leaks
To check whether each function is memory leaked, you can analyze it through the MemoryMonitor function in Android Studio. Memory Monitor also integrates HPROF Viewer and Allocation Tracker to analyze memory snapshots and memory allocation tracking. Another tool is recommended, Square's open source leakcanary, which is very simple and easy to use.
- When the process is initialized, the necessity of directly applying for objects that are resident in memory and static objects or singleton objects that are applied in other functions.
2 . Memory optimization
According to the memory section of the performance optimization model published by Google on youtube, you can optimize the memory of each function, or refer to Hu Kai's summary.
There are roughly the following, please refer to the original text:
- Use large heap with caution
- Design a suitable cache size in consideration of the memory threshold of the device and other factors
- onLowMemory vs onTrimMemory
- The resource file needs to be stored in the appropriate folder
- Try catch some large memory allocation operations
- Use static objects with caution
- Pay special attention to unreasonable holdings in singleton objects
- Cherish Services resources
- Optimize layout hierarchy and reduce memory consumption
- Use "abstract" programming with caution
- Serialize data using nano protobufs
- Use dependency injection framework with caution
- Use multi-process with caution
- Use ProGuard to remove unwanted code
- Use third-party libraries with caution
Consider different implementations to optimize memory usage
- Pay attention to the leak of Activity
- Consider using Applicaiton Context instead of Activity Context
- Pay attention to the timely recycling of temporary Bitmap objects
- Pay attention to the logout of the listener
- Pay attention to the leak of objects in the cache container
- Pay attention to the leak of Webview
Pay attention to the timely closure of Cursor objects
- Reuse the resources that come with the system
- Reuse of ConvertView in ListView
- Multiplication of Bitmap objects
- Avoid executing object creation in ondraw method
StringBuilder instead of String
- Use a lighter data structure
- Avoid using enum in Android
- Reduce the memory usage of Bitmap objects
Use smaller images
- Reduce the memory usage of objects
- Reuse of memory objects
- Avoid memory leaks in objects
- Optimization of memory usage strategy
The above is a detailed explanation of the memory allocation and OOM issues in Android virtual machines. For more information about the memory allocation of OOM on Android virtual machines, please pay attention to my other related articles!