# Normal, Soft, Weak, Phantom References in Java

/This article is just for self-learning.

### Normal 强引用

```java
final M m = new M();
m = null;
```

This is usually how we define an object. Once `m` is reassigned to `null`, the original assigned `new M()` will be garbage collected. So, a normal reference object will be garbage collected only when its reference is gone.

## Soft 软引用

```java
import java.lang.ref.SoftReference;

final SoftReference<byte[]> m = new SoftReference<>(new byte[1024 * 1024 * 10]);
System.out.println(m.get()); // can print
System.gc();
System.out.println(m.get()); // Still can print

final byte[] newBytes = new byte[1024 * 1024 * 15]; // 15 MB
System.out.println(m.get()); // cannot print, it's been garbage collected.
```

In the example above, `m` is a normal reference that refers to the object which is the `new SoftReference<>` . However, `m.get()` is a soft reference that refers to the `new byte[1024 * 1024 * 10]` which size is 10MB.

Suppose your heap is only 20MB (by setting `-Xmx20M`), once we define another bytes array `b` that is 15MB, then it will run out of heap capacity, so the original collected 10MB bytes array in soft reference will be garbage collected. If our heap is more than 25MB in this case, then that 10MB bytes array will not be collected.

In general, soft reference is usually used as a **cache** and it has lower priority than normal reference.

## Weak 弱引用

```java
import java.lang.ref.WeekReference;

final WeekReference<M> m = new WeekReference<>(new M());
System.out.println(m.get()); // can print
System.gc();
System.out.println(m.get()); // cannot print
```

similar to soft reference, `m` is a normal reference that refers to `new WeekReference<>()`, and `m.get()` is a weak reference that refers to `new M()`.

However, weak reference objects will always be garbage collected when we call `System.gc()`.

In general, the weak reference object has lower priority than the soft reference.

## Phantom 虚引用

```java
import java.lang.ref.PhantomReference;

final static LinkedList<Object> l = new LinkedList<>();
final static ReferenceQueue<M> q = new ReferenceQueue<>();
final M m = new M();
final PhantomReference<M> pr = new PhantomReference<>(m, q);

new Thread(() -> {
    while (true) {
        l.add(new bytes[1024 * 1024]);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println(pr.get()); // it will never print
    }
}).start();

new Thread(() -> {
    while(true) {
        Reference<? extends M> poll = q.poll();
        if (poll != null) {
            System.out.println("m is garbage collected: " + poll); // will print once m is garbage collected.
        }
    }
}).start();
```

The phantom reference is most like a non-reference. In the above example, when `m` is garbage collected, its object will be saved into `q` .

The interesting thing is that you will always get `null` when you try to call `System.out.println(pr.get());`. Then, why do we need a weak reference? The weak reference is usually applied in managing the system memory, which is out of JVM and is not controlled by garbage collection. Once an object is cleaned by garbage collection, we can be notified by monitoring the `queue`, then we can clean the value from the system memory as well.
