Android uses soft reference and weak reference to avoid OOM

  • 2021-07-01 08:09:51
  • OfStack

I think many friends are familiar with OOM (OutOfMemory), but how to effectively solve this problem when encountering this mistake? Today, we will talk about how to use soft reference and weak reference to effectively solve OOM problems in programs.

1. Understand the concepts of strong reference, soft reference, weak reference and virtual reference

In Java, although programmers do not need to manually manage the lifecycle of objects, soft references and weak references are needed if some objects are expected to have a fixed lifecycle (for example, JVM will automatically recycle some objects when there is insufficient memory to avoid errors in OutOfMemory).

Beginning with Java SE 2, four types of references are available: strong, soft, weak, and virtual. There are two main purposes for providing these four reference types in Java: the first is to let programmers decide the life cycle of certain objects through code; Second, it is beneficial for JVM to carry out garbage collection. Let's explain the concepts of these four types of references under 1:

1. Strong Citation (StrongReference)

Strong references are ubiquitous in program code, such as object and str in the following code:


Object object = new Object();
String str = "hello"; 

JVM does not recycle an object as long as it has a strong reference associated with it, and JVM would rather throw an OutOfMemory error than recycle the object even in the case of low memory. For example, the following code:


public class Main {
public static void main(String[] args) {
new Main().fun1();
}
public void fun1() {
Object object = new Object();
Object[] objArr = new Object[1000];
}
}

When running to Object [] objArr = new Object [1000]; If memory is low, JVM throws an OOM error and does not recycle the object pointed to by object. Note, however, that after fun1 runs, object and objArr no longer exist, so the objects they point to will be recycled by JVM.

If you want to break the association between a strong reference and an object, you can explicitly assign the reference to null, so that JVM will recycle the object at the appropriate time.

For example, in the clear method of the Vector class, the cleanup work is realized by assigning the reference to null:


/**
* Removes the element at the specified position in this Vector.
* Shifts any subsequent elements to the left (subtracts one from their
* indices). Returns the element that was removed from the Vector.
*
* @throws ArrayIndexOutOfBoundsException if the index is out of range
* ({@code index < 0 || index >= size()})
* @param index the index of the element to be removed
* @return element that was removed
* @since 1.2
*/
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
Object oldValue = elementData[index];
int numMoved = elementCount - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--elementCount] = null; // Let gc do its work
return (E)oldValue;
}

2. Soft Reference (SoftReference)

Soft references are used to describe objects that are useful but not required and are represented in the Java class java. lang. ref. SoftReference. For objects associated with soft references, JVM recycles the object only when memory is low. Therefore, this point can be used to solve the problem of OOM, and this feature is very suitable for caching: such as web page caching, picture caching and so on.

A soft reference can be used in conjunction with a reference queue (ReferenceQueue), and if the object referenced by the soft reference is recycled by JVM, the soft reference is added to the reference queue associated with it. Here is a usage example:


import java.lang.ref.SoftReference;
public class Main {
public static void main(String[] args) {
SoftReference<String> sr = new SoftReference<String>(new String("hello"));
System.out.println(sr.get());
}
}

3. Weak Reference (WeakReference)

Weak references are also used to describe non-essential objects. When JVM garbage collects, the objects associated with weak references will be collected regardless of sufficient memory. In java, it is represented by java. lang. ref. WeakReference class. The following is a usage example:


import java.lang.ref.WeakReference;
public class Main {
public static void main(String[] args) {
WeakReference<String> sr = new WeakReference<String>(new String("hello"));
System.out.println(sr.get());
System.gc(); // Notice JVM Adj. gc Carry out garbage collection 
System.out.println(sr.get());
}
}

The output is:

hello
null

The second output is null, which means that as long as JVM garbage collects, objects associated with weak references must be collected. Note, however, that an object associated with a weak reference here means that only a weak reference is associated with it, and if there is a strong reference associated with it at the same time, the object will not be recycled when garbage collection occurs (the same is true for soft references).

A weak reference can be used in conjunction with a reference queue (ReferenceQueue), and if the object referenced by the weak reference is recycled by JVM, the soft reference is added to the reference queue associated with it.

4. Virtual Reference (PhantomReference)

Virtual references are different from the previous soft references and weak references in that they do not affect the life cycle of objects. In java, it is represented by java. lang. ref. PhantomReference class. If an object is associated with a virtual reference, it may be collected by the garbage collector at any time, just as if there is no reference associated with it.

Note that a virtual reference must be used in association with a reference queue. When the garbage collector prepares to recycle an object, if it finds that it still has a virtual reference, it will add this virtual reference to the reference queue associated with it. The program can determine whether the referenced object will be garbage collected by judging whether a virtual reference has been added to the reference queue. If the program finds that a virtual reference has been added to the reference queue, it can take the necessary action before the memory of the referenced object is reclaimed.


import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class Main {
public static void main(String[] args) {
ReferenceQueue<String> queue = new ReferenceQueue<String>();
PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);
System.out.println(pr.get());
}
}

2. Take a step further to understand soft and weak references

For strong references, we often use them when writing code. For the other three types of references, soft reference and weak reference are used most, which have both similarities and differences. They are all used to describe non-essential objects, but objects associated with soft references are only recycled when memory is low, while objects associated with weak references are always recycled when JVM garbage collects.

In the SoftReference class, there are three methods, two constructors, and one get method (similar to WekReference):

Two constructions:


public SoftReference(T referent) {
super(referent);
this.timestamp = clock;
}
public SoftReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
this.timestamp = clock;
}

The get method is used to get a reference to the object associated with the soft reference and returns null if the object is recycled.

When using soft and weak references, we can explicitly notify JVM of garbage collection via System. gc (), but note that JVM will be executed immediately despite the notification, which means that this sentence does not guarantee that JVM1 will garbage collection at this time.

3. How to use soft reference and weak reference to solve OOM problem

Having talked about the basics of soft and weak references, how can we use them to optimize program performance and avoid the problems of OOM?

For example, if an application needs to read a large number of local pictures, if the pictures are read from the hard disk every time, the performance will be seriously affected, but if all the pictures are loaded into memory, it may cause memory overflow. At this time, soft reference can solve this problem.

The design idea is that an HashMap is used to save the mapping relationship between the path of a picture and the soft reference associated with the corresponding picture object. When the memory is insufficient, JVM will automatically reclaim the space occupied by these cached picture objects, thus effectively avoiding the problem of OOM. In Android development, it is often used for downloading a large number of pictures.

The following code is taken from the blog:

http://blog.csdn.net/arui319/article/details/8489451


private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();
<br>....
public void addBitmapToCache(String path) {
//  Strongly referenced Bitmap Object 
Bitmap bitmap = BitmapFactory.decodeFile(path);
//  Soft referenced Bitmap Object 
SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
//  Add the object to the Map Cache it in 
imageCache.put(path, softBitmap);
}
public Bitmap getBitmapByPath(String path) {
//  Object for taking soft references from the cache Bitmap Object 
SoftReference<Bitmap> softBitmap = imageCache.get(path);
//  Determine whether there is a soft reference 
if (softBitmap == null) {
return null;
}
//  Take out Bitmap Object, if due to insufficient memory Bitmap Is recycled and will get empty 
Bitmap bitmap = softBitmap.get();
return bitmap;
} 

Of course, here we hand over the cache replacement strategy to JVM for implementation, which is a relatively simple processing method. Complex 1 point cache, we can design a class independently, which involves the problem of cache strategy. For details, please refer to the previous blog post: "Cache Algorithm (Page Replacement Algorithm)-FIFO, LFU, LRU"


Related articles: