在Java中有引用对象, 引用对象又分为强软弱虚四种
强引用
首先是强引用, 也就是普通引用:只要有一个引用指向了对象, java垃圾回收器就不会回收这个对象, 这就是普通引用(强引用), 当一个对象没有引用指向时就会被回收.
import java.io.IOException;
public class test01 {
public static void main(String[] args) throws IOException {
M m = new M();
// m = null;
System.gc();
System.in.read();
}
}
class M {
@Override
protected void finalize() throws Throwable{
System.out.println("finalize");
//当这个对象打印finalize时说明这个对象被回收了
//正常情况下是不需要也不能重写这个回收函数
}
}
代码的结果是永远不停止, 如果把m = null, 那么M对象将会被回收, 回收机制
软引用
引用m指向一个软引用对象, 软引用对象又指向一个10M的数组
import java.lang.ref.SoftReference;
public class test02 {
public static void main(String[] args) {
SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]);//软引用 软引用对象里面有一个对象指向了一个10M的字节数组
//m = null;
System.out.println(m.get());
System.gc();
try {
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(m.get());
//再分配一个数组, heap将装不下,这时系统会垃圾回收,先回收一次,如果不够,会把软引用干掉
byte[] b = new byte[1024*1024*15];
System.out.println(m.get());
}
}
假定内存大小为20M, 为m分配了10M大小的空间, 又重新创建一个字节数组, 大小为15M, 这时m的内存就会被垃圾回收干掉, 因为内存不够用.
用途: 缓存
弱引用
import java.lang.ref.WeakReference;
public class test03 {
public static void main(String[] args) {
//弱引用碰到gc就会回收
WeakReference<M> m = new WeakReference<>(new M());
System.out.println(m.get());
System.gc();
System.out.println(m.get());
}
}
m引用指向一个弱引用对象, 弱引用对象(弱弱地)指向M对象, 如果一个强引用指向这个M, 当这个强引用被回收时, 弱引用会被自动回收.
ThreadLocal<M> tl = new ThreadLocal<>();
tl.set(new M());
tl.remove();
ThreadLocal中的map中的键是当前这个对象 tl , key值弱引用指向ThreadLocal, 因为Thread往往是长期存在的, 如果key不是弱引用, 那么将一直不会被回收, 此时就造成了内存泄漏, 使用弱引用指向ThreadLocal, 当tl对象被回收时, 这个key就会自动消失.
尽管如此, 还是会有内存泄漏存在, ThreadLocal被回收, key值也变为null, 则导致整个Value再也无法被访问, 因此依然存在内存泄漏, 所以使用ThreadLocal, 对象不使用了, 务必remove掉
这也是ThreadLcao最需要注意的地方
WeakHashMap的作用
虚引用
虚引用被回收时, 这个虚引用会装到这个队列中, 当这个对象被干掉时, 就会往这个队列扔进一个值
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.LinkedList;
import java.util.List;
public class test04 {
private static final List<Object> LIST = new LinkedList<>();
private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) {
PhantomReference<M> phantomReference = new PhantomReference<>(new M(),QUEUE);
new Thread(()->{
while (true){
LIST.add(new byte[1024*1024]);
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
Thread.currentThread().interrupt();
}
System.out.println(phantomReference.get());
}
}).start();
new Thread(()->{
while (true){
Reference<? extends M> poll =QUEUE.poll();
if(poll!=null){
System.out.println("虚引用对象被jvm回收了"+poll);
}
}
}).start();
try {
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
虚引用是get到的值都是null
DirectByteBuffer直接内存, 是不被JVM直接管理的内存, 被操作系统管理. 当这个buffer为空, 那么没有办法回收, 就要用到虚引用, 当虚引用被回收时, 接到通知, 就到堆外内存去回收这个buffer.
Java堆外内存回收Unsafe类