java中的5种引用
强引用 不会回收
指创建一个对象并把这个对象赋给一个引用变量。
被GCRoot对象引用的对象是强引用对象
当强引用有引用变量指向时不会被垃圾回收,抛出OutOfMemory错误也不会回收这种对象。
如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null
GCRoot对象有以下几种类型:
虚拟机栈(栈帧中的本地变量表)中引用的对象。
即当前正被调用的方法的局部变量或参数,在方法执行期间保持活跃。
方法区中类静态属性引用的对象。
由系统类加载器或引导类加载器加载的类的静态字段,
在类加载期间初始化,并且在类卸载之前一直存在。
方法区中常量引用的对象。
由final修饰的常量值,在编译期就已经确定,且在运行期不会改变。
本地方法栈中JNI引用的对象。
由Java调用非Java语言(如C或C++)实现的本地方法时产生的,
可以通过本地方法接口(JNI)访问虚拟机内部数据或操作系统资源。
软引用 一次gc后,内存任然不足,即回收软引用对象
被SoftReference对象所引用的对象称为软引用对象,
SoftReference对象调用get方法就会获取到它所软引用的那个对象。
软引用 用来描述一些有用但非必须的对象, 当JVM进行垃圾回收时内存空间足够,
垃圾回收器就不会回收软引用对象;但是当内存不够时会对软引用对象进行回收。
软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。
当然,当内存被gc后,就无法get访问到了
也有些软引用数据,可以实时清理,就可以配合引用队列来清理,(先进先出)
例:
List<SoftReference<byte[]>> list=new ArrayList<>();
创建引用队列
ReferenceQueue<byte[]> queue=new ReferenceQueue<>{};
//关联软引用和引用队列
SoftRefef=rence<byte[]> ref=new softReference<>(new SoftReference<>(new byte[_1MB],queue));
list.add(ref);
//提取并清除无用软引用对象
while(queue.poll()!=null){
list.remove(queue.poll());
}
弱引用 发现即回收
只被WeakReference对象引用的对象称为弱引用对象,弱引用也是用来描述非必须对象的,
当gc垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。
一个对象被弱引用和这个对象没有引用的 gc垃圾回收 效果是一样的。
它和完全没有引用的区别是,在垃圾回收之前可以通过get访问到它。
弱引用在threadlocal中有实际应用场景
同样代码中也可以结合弱引用
典型应用场景:
缓存可以提高程序的性能和效率,但也会占用内存空间。
弱引用来存一些不重要但是常用的数据
引用队列ReferenceQueue: 虚引用和终结器引用要配合引用队列来使用
虚引用 发现即回收 对象回收跟踪(清理磁盘垃圾,直接内存)
被PhantomReference对象引用的对象称为虚引用对象
当gc垃圾回收时,无论内存是否充足,都会回收虚引用关联的对象。
就会将引用对象放入引用队列,会有线程来定时清理
虚引用唯一的作用就是对垃圾回收过程进行跟踪,当虚引用对象引用的对象被垃圾回收了
就将虚引用对象和垃圾地址加入引用队列,
然后java会定时来引用队列中查找任务,定时执行
如:调用方法Unsafe.freeMemory(addr),清理其中的 直接内存
在jvm中对 对外内存 的回收就是利用虚引用来实现。具体看堆外内存管理部分。
终结器引用 第二次 GC 时才回收
终结器引用和虚引用的方式很类似,它用来实现对象的finaliz()终结方法。
所有的类有父类Object类,Object类中有finaliz()终结方法
当对象重写了finaliz()终结方法后,对象没有强引用时
虚拟机 会自动为对象创建终结器引用,
当对象被gc垃圾回收时,先将终结器引用放到引用队列中
再用优先级别很低的线程finaliz handle线程来查询引用队列中有没有终结器引用
如果有,该线程就会调用finaliz()方法,执行终结方法
第二次 GC 时才回收被引用的对象。