In order to better understand the mechanism of SoftReferrence and WeakReference, we should first talk about the concept of object and object reference in Java.

An object is an instance of a class; Object references, which can be understood as identifiers for manipulating objects, are similar to Pointers in C speech.

For example

Map map = new HashMap();
Copy the code

A map is an object reference; The real object is created by new.

Obj1 and Obj2 are memory created with new, and in Java heap memory is used.

O1 and O2 are object references, and in Java object references within methods use stack memory. When the method completes execution, it is released.

The GC in Java is focused on heap memory of Obj1 and Obj2. A simple description of the GC principle is that when a memory object loses all references, the GC can reclaim it. Conversely, if the object still has a reference, it will not be collected by GC, even if the Java VIRTUAL machine throws an OutOfMemoryError.

A memory leak in Java is the retention of memory and how to access it (references) even when the object is no longer needed.

Take another extreme example

Vector v = new  Vector(10);  
for (int i = 1; i < 100; i++){  
    Object o = new  Object();  
    v.add(o);  
    o = null ;  
}
Copy the code

In this example, the code stack contains a reference to V for Vector and o for Object. In the For loop, we keep generating new objects, adding them to the Vector, and then emptying the O reference. The question is whether the Object we created can be collected by the GC if the O reference is null. The answer is no. As GC traces references in the code stack, it finds v references, and further down, it finds references to Object objects in the memory space that v references point to. That is, even though the O reference has been null, there are still other references to the Object that can be accessed, so the GC cannot release them. If the Object Object has no use for the program after this loop, the Java program is considered to have a memory leak.

When an Activity is closed, it does not release the memory occupied by the Activity because the static variable Activity still refers to the Activity.

static Activity activity;
public void setActivity(Activity a) {
    this.activity = a;
}
Copy the code

The following describes reference types in Java

  1. Strong reference (default)
Object obj = new Object();
Copy the code

If the object reference is not null, GC will never reclaim memory, even if OOM occurs.

Object obj = newObject(); . obj =null;// The object is collected for the garbage collector. When is it collected depends on the garbage collector's algorithm
Copy the code
  1. If the SoftReference space is sufficient, the garbage collector collects the reference object only when the memory space is close to the threshold and the JVM is about to release oom.
String sf = newString (" SoftReference "); SoftReference sfRefer =new SoftReference(sf);
sf = null;
Copy the code
  1. When garbage collector scans weakly referenced objects, they will be directly reclaimed by garbage collector regardless of whether the memory space is sufficient. Don’t worry too much though, the garbage collector is a low-priority thread, so it may not be quick to find weakly referenced objects.
String wf = newString (" WeakReference "); WeakReference sfRefer =new WeakReference(wf);
wf = null;
Copy the code

The SoftReference release time is described in the following example.

public class JavaTest {
    public static void main(String[] args) {
        byte[] strong1 = new byte[100000000];// It takes up a lot of memory

        byte[] soft = new byte[900000000];
        SoftReference softReference = new SoftReference(soft);
        soft = null;

// byte[] strong2 = new byte[900000000];

        System.out.println("SoftReference : "+ softReference.get()); }}// Here is the output
// SoftReference : [B@1b6d3586
// In this example, if you comment out the memory request for Strong2, the memory space has not reached the upper limit and therefore the memory pointed to by the soft reference has not been freed.
Copy the code
public class JavaTest {
    public static void main(String[] args) {
        byte[] strong1 = new byte[100000000];// It takes up a lot of memory

        byte[] soft = new byte[900000000];
        SoftReference softReference = new SoftReference(soft);
        soft = null;

        byte[] strong2 = new byte[900000000];// The current memory is not enough

        System.out.println("SoftReference : "+ softReference.get()); }}// Here is the output
// SoftReference : null
// In this example, when the memory request for Strong2 is turned on, the memory space reaches the upper limit, so the memory pointed to by the soft reference is freed.
Copy the code
public class JavaTest {
    public static void main(String[] args) {
        byte[] strong1 = new byte[100000000];// It takes up a lot of memory

        byte[] soft = new byte[900000000];
        SoftReference softReference = new SoftReference(soft);
// soft = null; // This line of code sets strong references to null and only keeps soft references to ensure that the memory is released when insufficient, otherwise OOM occurs

        byte[] strong2 = new byte[900000000];// The current memory is not enough

        System.out.println("SoftReference : "+ softReference.get()); }}// Here is the output
// Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
// After creating SoftReference in Java code, you must set the soft original object to NULL
Copy the code

Let’s take a look at the release time of WeakReference

public class JavaTest {
    public static void main(String[] args) {

        byte[] strong1 = new byte[100000000];// It takes up a lot of memory

        byte[] weak = new byte[900000000];
        WeakReference weakReference = new WeakReference<>(weak);
        weak = null;// Set strong references to null, only keep weak references, to ensure the release of the memory, otherwise OOM occurs

// System.gc(); // To force gc

// byte[] strong2 = new byte[900000000];

        System.out.println("WeakReference : "+ weakReference.get()); }}// Here is the output
// WeakReference : [B@1b6d3586
// When gc is not normally performed, the memory pointed to by the WeakReference reference is not freed
Copy the code
public class JavaTest {
    public static void main(String[] args) {

        byte[] strong1 = new byte[100000000];// It takes up a lot of memory

        byte[] weak = new byte[900000000];
        WeakReference weakReference = new WeakReference<>(weak);
        weak = null;// Set strong references to null, only keep weak references, to ensure the release of the memory, otherwise OOM occurs

        System.gc();// To force gc

// byte[] strong2 = new byte[900000000];

        System.out.println("WeakReference : "+ weakReference.get()); }}// Here is the output
// WeakReference : null
// In the case of GC, even if the memory limit is not reached, the memory pointed to by the WeakReference is freed
Copy the code
public class JavaTest {
    public static void main(String[] args) {

        byte[] strong1 = new byte[100000000];// It takes up a lot of memory

        byte[] weak = new byte[900000000];
        WeakReference weakReference = new WeakReference<>(weak);
        weak = null;// Set strong references to null, only keep weak references, to ensure the release of the memory, otherwise OOM occurs

// System.gc(); // To force gc

        byte[] strong2 = new byte[900000000];

        System.out.println("WeakReference : "+ weakReference.get()); }}// Here is the output
// WeakReference : null
// It can be seen that when the requested memory reaches the upper limit, gc may be performed and the memory pointed to by the WeakReference reference will be released
Copy the code

Let’s look at global reference objects

public class JavaTest {

    private static Map<String, WeakReference> weakMap = new HashMap<>();

    public static void main(String[] args) {

        byte[] strong1 = new byte[100000000];

        byte[] weak = new byte[900000000];
        WeakReference weakReference = new WeakReference<>(weak);
// weak = null;
        weakMap.put("weak", weakReference);

// System.gc();

        byte[] strong2 = new byte[900000000];

        System.out.println("WeakReference : " + weakMap.get("weak").get()); }}// Here is the output
// Exception in thread "main" java.lang.OutOfMemoryError: 
Copy the code

Next, let’s put the method of creating WeakReference into another method to see the running effect

public class JavaTest {

    private static Map<String, WeakReference> weakMap = new HashMap<>();

    public static void main(String[] args) {

        byte[] strong1 = new byte[100000000];

        newWeak();

// System.gc();

        byte[] strong2 = new byte[900000000];

        System.out.println("WeakReference : " + weakMap.get("weak").get());
    }

    private static void newWeak(a) {
        byte[] weak = new byte[900000000];
        WeakReference weakReference = new WeakReference<>(weak);
// weak = null;
        weakMap.put("weak", weakReference); }}// Here is the output
// WeakReference : null
// It can be seen that in newWeak, the variable weak is not set to null. When the memory is insufficient, the memory in WeakReference will also be released
// After the newWeak method ends, the weak reference is automatically set to null
Copy the code