As is known to all, each Android application has a certain memory limit at run time, and the limit is typically 16MB or 24MB (depending on the platform). Therefore, in the development of applications need to pay special attention to their own memory usage, and generally the most memory resources, usually pictures, audio files, video files and other multimedia resources; Since the Android system does the processing of audio, video and other resources, it does not load the entire file into memory. There is generally no memory overflow (hereinafter referred to as oom) errors, so their memory consumption issues are not covered in this article. This article focuses on the memory consumption of the picture, and if you are developing a picture browser application, such as an app like the one that comes with Android gallery, this problem will become particularly important, and if you are developing your current shopping client, you will sometimes encounter this problem if you do not handle it properly.
Currently encountered in the oom scene, there are several situations, but no matter what kind of situation, the idea of solving the problem is consistent.
(1) Display single picture, picture file volume reaches 3000*4000 level;
(2) When loading a large number of images at once in a ListView or gallery control;
Introduction to related knowledge
1. Color model
The common color model has RGB, YUV, CMYK and so on, most of the image API used in the RGB model, Android is the same, in addition, in Android there is also a color model containing transparency alpha, namely ARGB. More detailed information about the color model is not covered in the scope of this article.
2. Digital coding of color values in computers
In the case of transparency, the color value of a pixel is represented in the computer in the following 3 ways:
(1) floating-point code: For example, float: (1.0, 0.5, 0.75), each color component accounted for 1 float field, where 1.0 indicates that the value of the component is full red or full green or full blue;
(2) 24-bit integer encoding: for example 24-bit: (255, 128, 196), each color component accounted for 8 bits, the value range 0-255, where 255 indicates that the value of the component is full red or full green or full blue;
(3) 16-bit integer encoding: for example 16-bit: (31, 45, 31), the 1th and 3rd color components accounted for 5 bits, the value range of 0-31, the 2nd color component accounted for 6 bits, the value range of 0-63;
In Java, a variable of type float is 32 bits, a variable of type int is 32 bits, and a variable of type short and char is 16 bits, so it can be seen that the color of a pixel is encoded by floating-point notation, the memory consumption is 96 bits or 12 bytes, and the 24-bit integer notation is used to encode the As long as an int type variable, occupies 4 bytes (high 8 bits empty, low 24 bits for color), and 16-bit integer notation, as long as a short type variable, accounting for 2 bytes, so you can see the integer representation of the color value, can greatly save memory, of course, The color quality will also be relatively low. An integer encoding is generally used when acquiring bitmap in Android.
The sequence of the components of R, G and B can be in RGB or bgr,android in the notation of the above 2 integer encodings, and this article is also discussed in this order. In 24-bit integer notation, because the R, G, B components accounted for 8 bits, sometimes the industry also refers to RGB888 to refer to this information; Similarly, in 16-bit integer notation, the R, G, and B components accounted for 5, 6, 5, respectively, referring to this information as RGB565.
Now consider the color coding of transparency, in fact, the same way as the non-transparent encoding: The 24-bit integer encoding RGB model takes the INT type variable, its idle high 8 bits is precisely used to place the transparency component, where 0 is full transparency, 255 is completely opaque, and according to the order of a, R, G, B, Can be summed up in the case of ARGB8888, and the 16-bit integer encoding of the RGB model with the short type variable, the adjustment of the components accounted for a number of 4 bits, then just 4 bits can be vacated to encode the transparency value, according to the order of a, R, G, B, You can summarize this situation with ARGB4444. Recall that Android's Bitmapconfig class, with constants such as argb_8888, argb_4444, and RGB565, can now tell what they mean respectively. It is also possible to calculate the size of an image in memory, such as loading a 1920*1200 image with argb_8888 encoding, and presumably occupying 1920*1200*4/1024/1024=8.79MB's memory.
3.Bitmap in-memory storage area
http://www.7dot9.com/2010/08/android-bitmap%E5%86%85%E5%AD%98%E9%99%90%E5%88%B6/, this article discusses the problem of Android memory limitation, The author thinks that the bitmap object is pointing to the bitmap object on the heap through a reference on the stack, and the bitmap object corresponds to a native image that uses the external store, actually using byte[] to store the memory space. However, to ensure the external allocation of memory is successful, you should ensure that the currently allocated memory plus the memory value that is currently allocated is not larger than the maximum memory value for the current heap, and that memory management completely treats external memory as part of the current heap.
Reference types for 4.Java objects
(1) strong reference (Strongreference) If an object has a strong reference, the garbage collector will never recycle it. When there is not enough memory space, the Java virtual Machine prefers to throw a outofmemoryerror error, which causes the program to terminate abnormally, and does not rely on random recycling of strongly referenced objects to resolve out-of-memory issues.
(2) Soft Reference (SoftReference) If an object has only soft references, the memory space is sufficient, and the garbage collector does not recycle it, and if the memory space is insufficient, the memory of those objects is reclaimed. The object can be used by the program as long as it is not reclaimed by the garbage collector.
(3) A weak reference (WeakReference) weak reference differs from a soft reference in that an object with only a weak reference has a more ephemeral life cycle. As the garbage collector thread scans the area of memory it governs, once an object with only a weak reference is found, its memory is reclaimed, regardless of whether the current memory space is sufficient or not.
(4) virtual reference (phantomreference) "virtual reference" as the name implies, is the form of a dummy, and several other references are different, virtual reference does not determine the life cycle of the object. If an object holds only virtual references, it can be reclaimed by the garbage collector at any time, just as there are no references.
Common Scenarios for solving oom
Memory limitations are a system-level limitation for Android applications, and as an application-layer developer, there is no way to completely eliminate this limitation, but there are some ways to use memory wisely to circumvent this problem. Here are some of the most common ways that individuals summarize:
(1) Cache the image into memory, using soft reference cache to memory, instead of reloading to memory at each use;
(2) Adjust the image size, mobile phone screen size is limited, the display area assigned to the image itself is smaller, sometimes the image size can be adjusted appropriately;
(3) Using low memory consumption of encoding, such as Bitmap.Config.ARGB_4444 than Bitmap.Config.ARGB_8888 more memory;
(4) Timely recovery of images, if the reference to a large number of bitmap objects, and the application does not need to display all the pictures at the same time, can be temporarily used bitmap objects timely recovery;
(5) Custom heap memory allocation size, optimize the Dalvik virtual machine heap memory allocation;
This article will be the first 4 ways to do the demonstration and analysis.
Demo Test Description
In order to illustrate the scenario of Oom and the way to solve oom, I made an Android application--oomdemo to demonstrate that the basic situation of this application is as follows:
(1) The application shows a gallery, the gallery load only the picture, gallery The path of the image in the adapter, not the picture object itself, adapter dynamically load the picture;
(2) The pictures used in the demo are pre-stored in the cache directory of SDcard, and the filenames are a.jpg,b.jpg...r.jpg, a total of 18;
(3) The picture is the JPG picture of the specification 1920*1200, the file size is within the 423KB-1.48MB range;
(4) Operating environment: Simulator--android2.2 Version System--480*320 screen size, Moto defy--2.3.4 version CM7 system--854*480 screen size;
(5) Program basic structure diagram:
Presentation Results and Description
1. Demonstrate a
First of all, the simplest way to load images, without any image caching, resizing or recycling, simpleimageloader.class is to assume this responsibility. The code for loading the picture section is as follows:
@Override
Public Bitmap loadbitmapimage (String path) {
return Bitmapfactory.decodefile (path);
}
@Override
Public drawable loaddrawableimage (String path) {
return new bitmapdrawable (path);
}
Demo Result: The emulator slice can only load 1-3 sheets, then an oom error occurs, no error occurs on defy, because the memory limit is different, defy is running third-party ROM, memory allocation is 40MB. In addition gallery every time a picture, you have to re-parse to get a picture, although there is no error on the defy, but when the image volume increased, GC recovery is not timely, there is still the possibility of oom.
2. Demo Two
Add a soft reference cache for the picture load, each time the picture gets the picture object from the cache, and if it doesn't exist in the cache, the picture is loaded from SDcard and the object is added to the cache. Also, soft-referenced objects can help the GC reclaim them when they are insufficient. Imageloaderwithcache.class responsible for this responsibility, the key code is as follows:
Private hashmap<string, softreference<bitmap>> Mimagecache;
@Override
Public Bitmap loadbitmapimage (String path) {
if (Mimagecache.containskey (path)) {
softreference<bitmap> softreference = mimagecache.get (path);
Bitmap Bitmap = Softreference.get ();
if (null! = Bitmap)
return bitmap;
}
Bitmap Bitmap = bitmapfactory.decodefile (path);
Mimagecache.put (Path, new softreference<bitmap> (Bitmap));
return bitmap;
}
@Override
Public drawable loaddrawableimage (String path) {
return new Bitmapdrawable (Loadbitmapimage (path));
}
Demo Result: On the simulator, you can load more than 1-2 pictures on the cache, but there will still be oom; there is no error on defy. Since the images used in this case are relatively memory-based, the GC is still not able to completely avoid oom when it has not yet recovered the soft reference object, and then it has to apply for more than the remaining amount of memory space. If you load a large number of small images, such as 100*100 specifications, the role of soft references in the cache may be played out. (this hypothesis can be further tested to prove it)
3. Demo Three
To further avoid oom, in addition to caching, images can be compressed, further saving memory, in most cases resizing the picture will not affect the application's expressiveness. Imageloaderwithscale.class is responsible for this responsibility, the sizing code is as follows:
Bitmapfactory.options Options = new Bitmapfactory.options ();
Options.injustdecodebounds = true;
Bitmapfactory.decodefile (path, options);
if (Options.mcancel | | options.outwidth = =-1 | | options.outheight = =-1) {
LOG.D ("Oomdemo", "alert!!!" + string.valueof (options.mcancel) + "" + Options.outwidth + options.outheight);
return null;
}
Options.insamplesize = util.computesamplesize (options, +, (int) (1 * 1024 * 1024));
LOG.D ("Oomdemo", "insamplesize:" + options.insamplesize);
Options.injustdecodebounds = false;
Options.indither = false;
Options.inpreferredconfig = Bitmap.Config.ARGB_8888;
Bitmap Bitmap = bitmapfactory.decodefile (path, options);
Demo Result: In the above code, the boundary of the image is decoded first, the image width and height can be obtained without the need to get the bitmap object (the width and height values are set to the Options.outwidth and options.outheight two attributes respectively). Computesamplesize the parameters for this method are "bitmapfactory.options required to parse the picture", "minimum width or high value of the resized picture", and "upper memory footprint of the resized picture". In combination with the width of the original image, this method calculates an adjustment scale, adjusts the original image and loads it into memory, and the image consumes no more memory than is previously specified. In the simulator, when you limit the memory size of a picture to 1*1024*1024, you can load more pictures than uncompressed, but you will still get oom, and if you limit the memory size of the image to 0.5*1024*1024, you can load all the pictures completely. So resizing a picture is still a good way to save memory. There is no error in defy, as in the same reason.
4. Demo Four
In some cases, the severe reduction of the image will affect the display of the application, so it is necessary to reduce the image as little as possible to display the picture, the manual to recycle the picture becomes particularly important. In the class Imageloaderwithrecyle.class, you have added a way to reclaim your picture resources:
@Override
public void Releaseimage (String path) {
if (Mimagecache.containskey (path)) {
softreference<bitmap> reference = mimagecache.get (path);
Bitmap Bitmap = Reference.get ();
if (null! = Bitmap) {
LOG.D ("Oomdemo", "recyling" + path);
Bitmap.recycle ();
}
Mimagecache.remove (path);
}
}
Demo Result: Picture compression limit is still maintained in 1*1024*1024, in adapter, call Releaseimage method in time, reclaim temporarily unwanted picture. At this point in the simulator has never been an oom, so overall, the comprehensive cache, sizing, recycling and other means, or can effectively avoid oom.
5. Optimize heap memory allocation for Dalvik virtual machines
For Android platforms, the Dalvik JAVAVM used by its hosting layer has many things to optimize for its current performance, such as the possibility of manually interfering with GC processing in the development of some large-scale games or resource-consuming applications, using The Settargetheaputilization method provided by the Dalvik.system.VMRuntime class can enhance the processing efficiency of the program heap memory. Of course, we can refer to the specific principle of open source engineering, here we only say how to use: The code is as follows:
Private final static floattarget_heap_utilization = 0.75f;
Can be called when the program is OnCreate
Vmruntime.getruntime (). Settargetheaputilization (target_heap_utilization);
Can
6. How much memory is needed to customize our application
Private final static int cwj_heap_size = 6* 1024* 1024;
Set minimum heap memory to 6MB size
Vmruntime.getruntime (). Setminimumheapsize (Cwj_heap_size);
Summary
This article introduces the soft reference cache, sizing, recycling and other means to avoid oom, the overall effect is obvious. But in the actual application scenario, the picture's application does not want this article to demonstrate the simple, sometimes the picture resources may come from with the network, then needs to cooperate the asynchronous loading the way to download the picture first and through the callback method to display;