ANDROID memory optimization (big summary)

ANDROID memory optimization (big summary)

Memory leaks can cause many problems:
1. The program freezes, and the response speed is slow (the JVM virtual machine frequently triggers GC when the memory usage is high)
2. Inexplicably disappears (when your program occupies more memory, it is in the background The more likely it is to be killed. On the contrary, the smaller the memory footprint, the longer it will exist in the background)
3. Direct crash (OutOfMemoryError)
Problems faced by ANDROID memory:
1. Limited heap memory, the original is only 16M
2. Memory size consumption Depending on the device, operating system level, screen size, etc.
3. The program cannot be directly controlled
4. Support background multitasking (multitasking)
5. Run on a virtual machine
This article mainly uses the following 5R method to control ANDROID Memory optimization:
1. Reckon (calculation)
first needs to know the memory consumption of your app, knowing yourself and knowing the enemy can survive the battle
2. Reduce (reduce)
consumes less resources
3. Reuse (reuse)
when it is used up for the first time, Try to give other uses
5. Recycle (recycle)
to return resources to the production flow
4. Review (check) to
review your program to see what is unreasonable in the design or code.
Reduce means to reduce, and directly reducing the use of memory is the most effective optimization method.
Let's take a look at what methods can reduce memory usage:
Bitmap is a big memory consuming user. Most of the OOM crashes are generated when operating Bitmap. Let's take a look at how to deal with pictures:
Picture display: We need to load the size of the picture according to the demand. For example, the list is only used to load thumbnails when previewing (thumbnails). Only when the user clicks on a specific item and wants to see the detailed information, another fragment/activity/dialog box will be launched at this time to display the size of the entire picture:
directly using ImageView to display the bitmap will take up more resources, especially if the picture is large It may cause a crash.
Use BitmapFactory.Options to set inSampleSize, which can reduce the requirements for system resources.
The attribute value inSampleSize indicates that the thumbnail size is a fraction of the original picture size, that is, if the value is 2, the width and height of the retrieved thumbnail are both 1/2 of the original picture, and the picture size is 1 of the original size./4.

1 BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options(); 2 bitmapFactoryOptions.inJustDecodeBounds = true; 3 bitmapFactoryOptions.inSampleSize = 2; 4//Here we must set it back to false, because we set it to true before 5//After setting inJustDecodeBounds to true, decodeFile does not allocate space, that is, the Bitmap decoded by BitmapFactory is Null, but the length and width of the original image can be calculated 6 options.inJustDecodeBounds = false; 7 Bitmap bmp = BitmapFactory.decodeFile(sourceBitmap, options); Picture pixels: There are four attributes of pictures in Android, namely: ALPHA_8: Each pixel occupies 1 byte of memory ARGB_4444: Each pixel occupies 2byte memory ARGB_8888: Each pixel occupies 4byte memory (default) RGB_565: Each pixel occupies 2byte memory The default color mode of Android is ARGB_8888, which has the most delicate colors and the highest display quality. But again, it takes up the largest amount of memory. Therefore, use RGB_565 (565 has no transparency attribute) when the effect on the picture is not particularly high, as follows: [java] view plaincopyprint? 8 publicstaticBitmapreadBitMap(Contextcontext, intresId) { 9 BitmapFactory.Optionsopt = newBitmapFactory.Options(); 10 opt.inPreferredConfig = Bitmap.Config.RGB_565; 11 opt.inPurgeable = true; 12 opt.inInputShareable = true; 13//Get resource pictures 14 InputStreamis = context.getResources().openRawResource(resId); 15 returnBitmapFactory.decodeStream(is, null, opt); 16} Copy code

Image recycling:
After using Bitmap, you need to call the Bitmap.recycle() method in time to release the memory space occupied by the Bitmap, instead of waiting for the Android system to release it.
The following is a sample code snippet to release Bitmap.

17//First judge whether it has been recycled 18 if(bitmap != null && !bitmap.isRecycled()){ 19//Recycle and set to null 20 bitmap.recycle(); 21 bitmap = null; 22 } 23 System.gc(); Catch the exception: After the above optimizations, there will still be the risk of reporting OOM, so a final checkpoint is needed below-catching OOM exceptions: [java] view plaincopyprint? 24 Bitmap bitmap = null; 25 try { 26//Instantiate Bitmap 27 bitmap = BitmapFactory.decodeFile(path); 28} catch (OutOfMemoryError e) { 29//Catch OutOfMemoryError to avoid direct crash 30} 31 if (bitmap == null) { 32//If the instantiation fails, the default Bitmap object is returned 33 return defaultBitmapMap; 34} Copy code

Modify object reference type:
Reference type:
Reference is divided into four levels, the four levels from high to low are: strong reference>soft reference>weak reference>phantom reference.
Strong reference
such as: Object object=new Object(), object is a strong reference. When the memory space is insufficient, the Java virtual machine would rather throw an OutOfMemoryError error to cause the program to terminate abnormally, and would not solve the problem of insufficient memory by reclaiming objects with strong references at will.
Soft references (SoftReference)
are only reclaimed when the memory is insufficient, and are often used for caching; when the memory reaches a threshold, the GC will reclaim it;
objects with weak references have a shorter life cycle. In the process of the garbage collector thread scanning the memory area under its jurisdiction, once an object with only weak references is found, its memory will be reclaimed regardless of whether the current memory space is sufficient.
Phantom Reference (PhantomReference)
As the name suggests, "Phantom Reference" is nothing but a dummy. Unlike other types of references, a Phantom Reference does not determine the life cycle of an object. If an object holds only phantom references, it is the same as without any references, and may be garbage collected at any time.
Application examples of soft reference and weak reference:
Note: Bitmap caching scheme of SoftReference (soft reference) or WeakReference (weak reference) is now deprecated. Since Android 2.3 (API Level 9), the garbage collector focuses more on the recovery of soft/weak references, so the following content can be ignored.
In the development of Android applications, in order to prevent memory overflow, when dealing with some objects that occupy a large amount of memory and have a long life cycle, you can try to apply soft reference and weak reference technology.
The following takes the use of soft references as an example to explain in detail (the use of weak references is similar to soft references):
suppose our application will use a lot of default pictures, and these pictures will be used in many places. If you read the picture every time, because reading the file requires hardware operation, the speed is slow and the performance is lower. So we consider caching the image and reading it directly from the memory when needed. However, because pictures occupy a large amount of memory space, caching many pictures requires a lot of memory, and OutOfMemory exceptions may occur more easily. At this time, we can consider using soft reference technology to avoid this problem.
First define a HashMap to save the soft reference object.

35 private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>(); Let's define a method to save the soft reference of Bitmap to HashMap. [java] view plaincopyprint? 36 public void addBitmapToCache(String path) { 37//Strongly referenced Bitmap object 38 Bitmap bitmap = BitmapFactory.decodeFile(path); 39//Bitmap object of soft reference 40 SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap); 41//Add the object to the Map to make it cache 42 imageCache.put(path, softBitmap); 43} //When obtaining, you can get the Bitmap object through the get() method of SoftReference. 44 public Bitmap getBitmapByPath(String path) { 45//Get the soft-referenced Bitmap object from the cache 46 SoftReference<Bitmap> softBitmap = imageCache.get(path); 47//Determine whether there is a soft reference 48 if (softBitmap == null) { 49 return null; 50} 51//Take out the Bitmap object, if the Bitmap is recycled due to insufficient memory, it will be empty 52 Bitmap bitmap = softBitmap.get(); 53 return bitmap; 54} Copy code

After using soft references, the memory space of these cached image resources can be released before the OutOfMemory exception occurs, so as to prevent the memory from reaching the upper limit and avoid the occurrence of crashes.
It should be noted that before the garbage collector collects this Java object, the get method provided by the SoftReference class will return a strong reference to the Java object. Once the garbage thread collects the Java object, the get method will return null. Therefore, in the code for obtaining the soft reference object, it must be judged whether it is null, so as to avoid the occurrence of NullPointerException and cause the application to crash. When should we use soft references and when should we use weak references?
I personally think that if you just want to avoid the occurrence of OutOfMemory exceptions, you can use soft references. If you are more concerned about the performance of the application and want to reclaim some objects that take up a lot of memory as soon as possible, you can use weak references.
Also, it can be judged based on whether the object is frequently used. If the object may be used frequently, try to use soft references. If the object is more likely to be unused, a weak reference can be used.
In addition, the WeakHashMap is similar to the weak reference function. For a given key in WeakHashMap, the existence of its mapping does not prevent the garbage collector from reclaiming the key. After recycling, its entries are effectively removed from the map. WeakHashMap uses this mechanism implemented by ReferenceQueue.
Other small tips:
Use static final modifiers for constants.
Let's take a look at these two declarations in front of the class:
static int intVal = 42;
static String strVal = "Hello, world!";
The compiler will generate a method to initialize the class called clinit, which will be executed when the class is used for the first time. The method assigns 42 to intVal, and then assigns a reference to the constant table in the class to strVal. When these values are to be used in the future, they will be found in the member variable table. Let's make some improvements and use the "final" keyword:
static final int intVal = 42;
static final String strVal = "Hello, world!";
Now, the class no longer needs the clinit method, because when the member variable is initialized, it will Save the constant directly to the class file. The code that uses intVal is directly replaced with 42, and the code that uses strVal will point to a string constant instead of using member variables.
Declaring a method or class as final will not improve performance, but it will help the compiler optimize the code. For example, if the compiler knows that a getter method will not be overloaded, the compiler will call it inline.
You can also declare local variables as final, and again, this will not bring performance improvements. Using "final" can only make local variables look clearer (but sometimes this is necessary, such as when using anonymous inner classes).
Static methods instead of virtual methods
If you do not need to access the fields of an object, set the method to static, and the call will speed up by 15% to 20%. This is also a good practice, because you can see from the method declaration that calling the method does not need to update the state of the object.
Reduce unnecessary global variables
Try to avoid static member variables referencing instances that consume too much resources, such as Context
Because the Context reference exceeds its own life cycle, it will cause the Context to leak. So try to use the Context type of Application. You can easily get the Application object by calling Context.getApplicationContext() or Activity.getApplication().
Avoid creating unnecessary objects The
most common example is to use StringBuffer instead of String when you frequently manipulate a string.
For all the combinations of all basic types: the int array is better than the Integer array, which also summarizes the basic fact that two parallel int arrays perform much better than (int, int) object arrays.
In general, avoid creating short-lived temporary objects. Reducing the creation of objects can reduce garbage collection, thereby reducing the impact on the user experience.
Avoid internal Getters/Setters.
In Android, the cost of virtual method calls is much higher than direct field access. Usually according to the practice of object-oriented languages, it makes sense to use Getters and Setters in public interfaces, but direct access should be used in a class where a field is frequently accessed.
Avoid using floating point numbers The
general rule of thumb is that in Android devices, floating point numbers are twice as slow as integers.
It is better to use entity classes than interfaces.
Assuming you have a HashMap object, you can declare it as HashMap or Map:
Map map1 = new HashMap();
HashMap map2 = new HashMap();
Which is better?
According to the traditional view, Map would be better, because then you can change his specific implementation class, as long as this class inherits from the Map interface. The traditional view is correct for traditional programs, but it is not suitable for embedded systems. Calling a reference to an interface will take twice as long as calling a reference to an entity class. If HashMap is completely suitable for your program, then there is no value in using Map. If you are not sure about something, avoid using Map first, and leave the rest to the refactoring function provided by the IDE. (Of course the public API is an exception: a good API often sacrifices some performance) It is very convenient to
avoid the use of enumerations.
Enumeration variables are very convenient, but unfortunately it will sacrifice the speed of execution and greatly increase the file size.
Using enumerated variables can make your API better and provide compile-time checks. So in normal times you should undoubtedly choose enum variables for public APIs. But when performance is limited, you should avoid this approach.
For loop
access to member variables is much slower than access to local variables, such as the following piece of code:

55 for(int i =0; i <this.mCount; i++) {} Never call any method in the second condition of for, such as the following piece of code: [java] view plaincopyprint? 56 for(int i =0; i <this.getCount(); i++) {} It is best to change the above two examples to: [java] view plaincopyprint? 57 int count = this.mCount;/int count = this.getCount(); 58 for(int i =0; i <count; i++) {} The for-each syntax introduced in java1.5. The compiler saves the reference to the array and the length of the array into a local variable, which is very good for accessing array elements. However, the compiler will also generate an additional storage operation for local variables in each loop (such as the variable a in the following example), which will be 4 bytes more than the normal loop, and the speed is slightly slower: 59 for (Foo a: mArray) { 60 sum += a.mSplat; 61} Copy code

Understand and use the class library to
choose the code in the Library instead of rewriting it yourself. In addition to the usual reasons, considering that the system will use assembly code to call instead of the library method when the system is idle, this may be the best equivalent than the equivalent generated in the JIT The Java code is even better.
When you are dealing with strings, don't hesitate to use String.indexOf(), String.lastIndexOf() and other special implementation methods. These methods are implemented in C/C++, which are 10 to 100 times faster than Java loops.
System.arraycopy method is 9 times faster in self-coding loop on Nexus One with JIT.
The Formatter class under the android.text.format package provides methods such as IP address conversion and file size conversion; the DateFormat class provides various time conversions, which are very efficient methods.
The TextUtils class, Android provides us with a simple and practical TextUtils class for string processing. If you don t need to think about regular expressions to deal with simpler content, you might as well try this
high-performance MemoryFile class in android.text.TextUtils . Many people I complained that Android's low-level I/O performance is not ideal. If you don't want to use NDK, you can use the MemoryFile class to achieve high-performance file read and write operations. Where does MemoryFile apply? For I/O that requires frequent operations, mainly I/O operations related to external storage, MemoryFile maps the files on the NAND or SD card to the memory for modification processing, so that high-speed RAM is used instead. The performance of ROM or SD card is naturally improved, and for Android phones, it also reduces power consumption. There are not many functions implemented by this class, which are directly inherited from Object and executed directly at the bottom of C through JNI.
Reuse reuse, one of the important means to reduce memory consumption.
The core idea is to reuse existing memory resources and avoid creating new ones. The most typical use is Cache and Pool.
Bitmap cache:

Bitmap cache is divided into two types:
one is memory cache and the other is hard disk cache.
Memory cache (LruCache):
At the expense of precious application memory, memory cache provides fast Bitmap access. The LruCache class provided by the system is very suitable for caching Bitmap tasks. It stores the recently referenced objects in a strongly referenced LinkedHashMap, and releases the recently used objects after the cache exceeds the specified size.
Note: A very popular memory cache implementation used to be SoftReference (soft reference) or WeakReference (weak reference) Bitmap caching scheme, but it is no longer recommended. Since Android 2.3 (API Level 9), the garbage collector focuses more on the recovery of soft/weak references, which makes the above scheme quite ineffective.
Hard Disk Cache (DiskLruCache):
A memory cache is very helpful for accelerating access to recently viewed Bitmaps, but you can't be limited to the available pictures in memory. Components with larger data sets such as GridView can easily consume memory cache. Your application may be interrupted while performing other tasks (such as making a call), and tasks in the background may be killed or the cache may be released. Once the user resumes your application, you have to process each picture again.
In this case, the hard disk cache can be used to store the Bitmap and reduce the time (number of times) the picture is loaded after the picture is released by the memory cache. Of course, loading images from the hard disk is slower than the memory, and should be done in a background thread, because the hard disk read time is unpredictable.
Note: If the pictures are accessed very frequently, ContentProvider may be more suitable for storing cached pictures, such as applications like Image Gallery.
For more information about memory caching and hard disk caching, please see the official Google

Open source projects
for image caching : For image caching, open source projects tend to be used. Here I list a few I found:
1. Android-Universal-Image-Loader Image caching
is currently the most widely used image cache, supporting mainstream Most features of image caching.
Project address:
2. Picasso square open source picture cache
Project address:
Features: (1) It can automatically detect adapter reuse and cancel previous downloads
(2) Picture Transformation
(3) can load local resources
(4) can set occupant resources
(5) support debug mode
3. ImageCache image cache, including memory and Sdcard cache
Project address:
(1) Support Pre-fetch new pictures, support waiting queue
(2) includes secondary cache, can customize file name saving rules
(3) can choose a variety of cache algorithms (FIFO, LIFO, LRU, MRU, LFU, MFU, etc. 13) or self Define the cache algorithm
(4) It can easily save and initialize and restore data
(5) Support different types of network processing
(6) The cache can be initialized according to the system configuration, etc.
4. Android network communication framework Volley
we need to communicate with the network in our program, we generally use something like AsyncTaskLoader, HttpURLConnection, AsyncTask, HTTPClient (Apache), etc. In 2013, Google I/O released Volley . Volley is a network communication library on the Android platform, which can make network communication faster, simpler and more robust.
(1) Asynchronous downloading of JSON, images, etc.;
(2) Scheduling of network requests
(3) Priority processing of network requests
(4) Cache
(5) Multi-level cancellation requests
(6) and Activity and life Periodic linkage (Cancel all network requests at the same time when Activity ends)

Adapter is widely used in Android, especially in list. So adapter is the "distribution center" of data, so it is necessary to optimize its memory.
The following is a standard usage template:
mainly use convertView and ViewHolder for cache processing

62 @Override 63 public View getView(int position, View convertView, ViewGroup parent) { 64 ViewHolder vHolder = null; 65//If the convertView object is empty, create a new object, and reuse if it is not empty 66 if (convertView == null) { 67 convertView = inflater.inflate(..., null); 68//Create ViewHodler object 69 vHolder = new ViewHolder(); 70 vHolder.img = (ImageView) convertView.findViewById(...); 71 = (TextView) convertView.findViewById(...); 72//Save ViewHodler to Tag (Tag can receive Object type objects, so anything can be stored in it) 73 convertView.setTag(vHolder); 74} else { 75//When convertView is not empty, get View through getTag() 76 vHolder = (ViewHolder) convertView.getTag(); 77} 78//Assign a value to the object, modify the displayed value 79 vHolder.img.setImageBitmap(...); 80; 81 return convertView; 82} 83//Pack the displayed View into a class 84 static class ViewHolder { 85 TextView tv; 86 ImageView img; 87} Copy code

Pool (PooL)
object pool:
The basic idea of using the object pool is to save the used objects, and then use them again when they are needed next time, thereby reducing the frequent creation of objects to a certain extent s expenses. Not all objects are suitable for pooling-because maintaining the object pool also incurs a certain amount of overhead. Pooling objects that are not expensive at the time of generation may result in a situation where the "overhead of maintaining the object pool" is greater than the "overhead of generating new objects", thereby reducing performance. But for objects with considerable overhead during generation, pooling technology is an effective strategy to improve performance.
Thread pool:
The basic idea of thread pool is the idea of an object pool. It opens up a memory space in which many (undead) threads are stored. The thread execution scheduling in the pool is handled by the pool manager. When there is a thread task, one is taken from the pool, and the thread object is returned to the pool after the execution is completed. This can avoid the performance overhead caused by repeatedly creating thread objects and save system resources.
For example, if an application needs to interact with the network, there are many steps that need to access the network. In order not to block the main thread, a thread is created for each step. In the thread and the network interact, it becomes simple to use the thread pool. The thread pool is for the thread. A kind of encapsulation to make threads easier to use. You only need to create a thread pool, put these steps into the thread pool like tasks, and just call the thread pool's destruction function when the program is destroyed.

Java provides ExecutorService and Executors classes, we can use it to establish a thread pool.
Generally, the following 4 types can be established:

88/** Thread pool that only executes one task at a time*/ 89 ExecutorService singleTaskExecutor = Executors.newSingleThreadExecutor(); 90 91/** Thread pool that executes a limited number of tasks at a time*/ 92 ExecutorService limitedTaskExecutor = Executors.newFixedThreadPool(3); 93 94/** Thread pool where all tasks start at once*/ 95 ExecutorService allTaskExecutor = Executors.newCachedThreadPool(); 96 97/** Create a thread pool that can execute tasks in a specified time, or repeat execution*/ 98 ExecutorService scheduledTaskExecutor = Executors.newScheduledThreadPool(3); Copy code

Note: The
cache should be used appropriately according to the situation, because the memory is limited.
If you can save the path address, don't store the image data. If you don't use it frequently, try not to cache it, and empty it when not in use.