Article directory
strong reference
Both are strong references. Strong references are most commonly used in development. As long as there are references to objects, they will not be recycled by GC
// 我们自己定义的实体通过直接new的形式都是强引用
Object obj = new Object();
soft reference
General objects will not be recycled. When the application memory is about to be exhausted -> when OOM is about to occur, the garbage processor will recycle it, which can prevent the application from being down and unavailable due to OOM.
SoftReference<String> ref = new SoftReference<String>("aaa");
weak quotation
When the root reference becomes invalid, it will be recycled when the GC is triggered next time. Even if the root reference is reassigned after recycling, the reference will not be re-established
In the process of scanning the memory area under its jurisdiction by the garbage collector thread, once an object with only weak references is found, its memory will be reclaimed regardless of whether the current memory space is sufficient or not.
WeakReference<String> ref = new WeakReference<String>("aaa");
示例
String str=new String("333");
WeakReference<String>ref=newWeakReference<>(str);
System.out.println(ref.get());
str=null;
System.out.println(ref.get());
System.gc(); // 手动触发一次gc
System.out.println(ref.get());
Result: 333 333 null
dummy reference
Virtual references are not real references and do not affect normal garbage collection.
When the garbage collector decides to recycle the PhantomReference object, it will insert it into the ReferenceQueue.
PhantomReference.class
public class PhantomReference<T> extends Reference<T> {
public T get() {
return null;
}
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
For an object, this reference is useless, and it is the same as not having it. Phantom references must be used together with the reference queue. Its function is to track the garbage collection process and receive a system notification when the object is reclaimed by the collector. When the garbage collector is about to reclaim an object, if it finds that it still has a virtual reference, it will add this virtual reference to the reference queue after garbage collection, and will not completely destroy the object until its associated virtual reference is dequeued.
Virtual references are often ReferenceQueue
used in conjunction with reference queues
reference queue
ReferenceQueue
ReferenceQueue can be used with SoftReference/WeakReference/PhantomReference
refrenceQueue
In essence, it is a linked list, which ensures synchronized
thread safety, maintains volatile
the modified head
object, represents the current head object, and maintains the current number of queues
Take a look at how thread safety issues are guaranteed
static private class Lock {
};
private Lock lock = new Lock();
It can be seen that a global lock object is used here. This is an empty object, which exists only as a lock object. Its core is only to lock remove
methods and enqueue
methods (join queue and remove queue)
synchronized(lock){
// ...
}
When we call remove
a method, the method will be called to Object.wait
block, and when gc is triggered, enqueue
notifyAll will be called to notify the thread, which is not a cas operation, so it has little impact on performance
The following simulates a scenario. When our object is recycled by gc, the reference key in the map is removed.
public class Test {
private static ReferenceQueue<byte[]> referenceQueue = new ReferenceQueue<>();
private static int _1M = 1024 * 1024;
public static void main(String[] args) throws InterruptedException {
final Map<Object, MybObject> map = new HashMap<>();
Thread thread = new Thread(() -> {
try {
int n = 0;
MybObject k;
while (null != (k = (MybObject) referenceQueue.remove())) {
// 每次触发gc都会进来一次
System.out.println("gc:" + (++n));
map.remove(k.key);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.setDaemon(true);
thread.start();
// 创建1000个对象放入map中
for (int i = 0; i < 1000; i++) {
byte[] bytesKey = new byte[_1M];
byte[] bytesValue = new byte[_1M];
map.put(bytesKey, new MybObject(bytesKey, bytesValue, referenceQueue));
}
Thread.currentThread().join();
}
static class MybObject extends PhantomReference<byte[]> {
private Object key;
MybObject(Object key, byte[] referent, ReferenceQueue<? super byte[]> q) {
super(referent, q);
this.key = key;
}
}
}
operation result
gc:1
gc:2
...
gc:792
gc:793
gc:794
It can be seen that there is no recycling until 794 is recovered here, and the remaining 206 objects are still in the heap memory and have not been released
Note: The result is not the same under all computers, it is related to the computer, configuration, and jvm parameters, and the results are different each time
Cleaner class
From the figure below, you can see that Cleaner inherits the PhantomRefrence virtual reference class, which is essentially a Refrence.
The ReferenceHandler will continuously fetch the reference object from the pending list. The type of the reference object may be of any type. When the reference object is a Cleaner, the clean method of the Cleaner is called directly.
The usage method is also very simple, pass in the object instance and the runnable thread, and when the object is recycled, the run method of the runnable will be triggered
Cleaner.create(this, new Runnable() {
@Override
public void run() {
}
});
In most cases, strong references are used in development. In some special business scenarios, other reference types are also used in the development mode. It is recommended that you read this article carefully and use it as appropriate.