Easy Tutorial
❮ Github Tools Android Tutorial Customer Baseadapter ❯

Android Application OOM Issue Analysis and Solutions

Category Programming Technology

1. What is OOM?

03-21 21:05:28.771: E/dalvikvm-heap(13316): Out of memory on a 10485776-byte allocation.
03-21 21:05:28.779: E/AndroidRuntime(13316): java.lang.OutOfMemoryError

These lines mean that our program's request for 10485776 bytes is too large for the virtual machine to fulfill, leading to a shameful shutdown. This phenomenon usually occurs in the development of apps that use many images or very large images. In layman's terms, when our app needs to request a block of memory to store an image, the system thinks our app has already used enough memory. Even if it has 1GB of free memory, it does not agree to give our app more memory, and then the system immediately throws an OOM error. If the program does not catch this error, the app crashes with a pop-up.

2. Why does OOM occur?

Because the Android system has a maximum memory limit for each app process or each virtual machine. If the requested memory resources exceed this limit, the system will throw an OOM error. It is not very related to the remaining memory of the entire device. For example, an early Android system's virtual machine could have a maximum of 16M of memory. When an app starts, the virtual machine continuously requests memory resources to load images. When it exceeds the memory limit, an OOM occurs. How to determine the memory limit of an Android app?

2.1 Composition of Android App Memory:

App memory consists of Dalvik memory and native memory. Dalvik is the Java heap where created objects are allocated, and native memory is allocated through C/C++ methods, such as Bitmap. (After Android 3.0, the system defaults to Dalvik allocation, and native is managed as a heap.) The sum of these two parts should not exceed the Android memory limit for a single process or virtual machine.

What is the memory limit for each phone?

ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.getMemoryClass();

This method will return a number in M, which varies on different system platforms or devices, such as HTC default 24M, Galaxy 36M, emulator-2.3 24M, etc. My moto xt681 is 42M.

The above method retrieves the maximum memory resources of the virtual machine.

As for the size limit of the head heap, you can check the /system/build.prop file.

dalvik.vm.heapstartsize  =  5m
dalvik.vm.heapgrowthlimit = 48m
dalvik.vm.heapsize = 256m

Note:

2.2 Why does the Android system set a memory limit for apps?

1 To make developers use memory more reasonably. Limiting the upper limit of available memory for each application can prevent some applications from maliciously or inadvertently using too much memory, causing other applications to be unable to run normally. Android is multi-process; if one process (an app) consumes too much memory, other apps cannot run. With limits, developers must make good use of limited resources and optimize their use.

2 The screen display content is limited, and enough memory is sufficient. Even if there are thousands of pictures and millions of data that need to be used, the information that needs to be displayed to the user at a specific moment is always limited because the screen display is just so big, and the information that can be placed on it is very limited. Most information is in a state of being ready to display, so there is no need to give too much heap memory. In other words,

3 The need for multiple apps and multiple virtual machines with Davlik restrictions. Android apps use independent virtual machines, and each app opened will open at least one independent virtual machine. This can prevent a virtual machine crash from causing a system crash, and the cost is the need for more memory waste. This design ensures the stability of Android.

2.3 Isn't GC automatically recycling resources, so why does OOM still occur?

Android uses GC to automatically recycle unused memory resources to prevent app memory requests from accumulating more and more. However, GC generally recycles resources that are unowned objects or soft references, or even softer reference resources. For example:

``` Bitmap bt = BitmapFactory.decodeResource(this.getResources(), R.drawable.splash); //At this point, the image resource is a strong reference and has an owner. bt = null; //At this point, this image resource is unowned. GC will recycle it when it 5.1 Download a large number of images from the internet

For example, in the Weibo client: multi-threaded asynchronous network, the small rabbit directly uses LRUCache+SoftRef+Sd, and downloads large images on demand:

5.2 For situations where a listview, gridview, etc., needs to load a large number of entry information

There is a convertView parameter in the adapter's getView function, which tells you whether there is a reusable view object. If convertView is not used, a new view will be created every time getView is called, which can lead to a dramatic increase in memory, potentially causing an OutOfMemory error. Additionally, when reusing convertView, the existing images and other resources within it will become orphaned.

Google officially recommends using: "convertView + static ViewHolder class"

The official explanation is:

b Use the ViewHolder pattern to avoid unnecessary calls to findViewById; too many findViewById calls can also affect performance.

The role of the ViewHolder class is: The ViewHolder pattern stores a data structure in the tag of the view returned by the getView method. This data structure contains references to the views we want to bind data to, thus avoiding calling findViewById() each time getView() is called.

6 Memory allocation methods that exceed the memory limit:

6.1 Memory allocation from Native C. Using NDK (Native Development Kit) and JNI, it can allocate memory from the C level (such as malloc/free or new/delete), and such allocation is not counted within the 24MB limit. This is true, allocating memory from native code is for the convenience of Java, but it can be used to store data in RAM (even image data) that is a bit of a hit.

6.2 Use OpenGL textures. Texture memory is not counted in the limit. To see how much memory your application has actually allocated, you can use android.os.Debug.getNativeHeapAllocatedSize(). Using one of the two techniques introduced above, I can easily allocate 300MB for a single foreground process - more than 10 times the default 24MB limit. From the above, it can be seen that memory allocation using native code is not within the 24MB limit (the texture of OpenGL also uses native code to allocate memory).

**Click to share notes

Cancel

-

-

-

❮ Github Tools Android Tutorial Customer Baseadapter ❯