为了充分利用计算机的内存,对象被设计成拥有生命周期。当对象的生命周期结束,会被垃圾回收器回收,从而释放内存资源。为了考虑回收的各种场景,在JDK1.2引用了强、软、弱、虚4种引用类型。
强引用
如果一个对象是强引用,那么垃圾回收器不会轻易回收它。只用当这个对象没有被使用,垃圾回收器才会回收它。
创建一个new StrongReference()
,用一个引用strongReference
去指向这块内存空间的地址,当引用置为null
,垃圾回收器回收时,会出发finalize()
方法。我们来看运行结果。
StrongReference类被回收了!!!
如果这个对象一直被引用着,就算内存满了,也不会垃圾回收。宁愿抛出OutOfMemoryError
。
但是,如果你不精通内存的回收,千万不要使用finalize()
方法。
finalize()
的作用往往被认为是用来做最后的资源回收。此方法有很大的不确定性(不保证方法中的任务执行完)而且运行代价较高。所以用来回收资源也不会有什么好的表现。
这里还有一个梗,当年小米工程师,很多是从C++转Java的。C++一般会需要手动清理内存,所以习惯重写finalize()
方法。但是系统老是出现各种内存问题。最还是把垃圾清除的方法交给JVM。
软引用
当系统内存不足时,会触发GC。当垃圾回收后,内存还是不足,就会把软引用的包裹的对象给清理掉。
我们来测试test1()
。测试结果:
Student(grade=null)
这里对象并没有被回收,所以能拿到Student
。
我们再来测试下test2()
,为了模拟真实环境,这里将内存调整为20MB。
运行结果
[B@7960847b
[B@7960847b
null
当创建了两个字节数组后,内存满了,触发GC,Student
对象被回收。
那么软引用可以用于哪些场景呢?
软引用可以用来实现内存敏感的高速缓存,当系统空间不足时缓存对象可被清理掉而不影响业务。
弱引用
如果触发GC,这时内存很充足,但是被弱引用的对象还是会被回收。所以说,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。
运行结果
before gc: r=I'm here, static=I'm here
after gc: r=null, static=I'm here
如果是被WeakReference
包裹的对象,那么这个对象就是被弱引用的。我们看到GC后r.get=null
。但是sr.get()
还是有值的。如果被包裹的数据是静态的,即便被弱引用,也不会被GC回收的。
其实ThreadLocal
里面也运用到了弱引用哦。具体可以看看我之前的一篇文章:
“ ”
虚引用
这就是虚引用有几个特点:
-
无法通过虚引用来获取对一个对象的真实引用。
-
虚引用必须与
ReferenceQueue
一起使用,当GC准备回收一个对象,如果发现它还有虚引用,就会在回收之前,把这个虚引用加入到与之关联的ReferenceQueue
中。
运行结果:
null
那么给对象设置成虚引用有什么用呢?
为一个对象设置虚引用关联的唯一目的就是能在这个对象被垃圾收集器回收时收到一个系统通知。
还有会用虚引用管理堆外内存。
往期推荐
扫码二维码,获取更多精彩。或微信搜Lvshen_9,可后台回复获取资料
1.回复"java" 获取java电子书;
2.回复"python"获取python电子书;
3.回复"算法"获取算法电子书;
4.回复"大数据"获取大数据电子书;
5.回复"spring"获取SpringBoot的学习视频。
6.回复"面试"获取一线大厂面试资料
7.回复"进阶之路"获取Java进阶之路的思维导图
8.回复"手册"获取阿里巴巴Java开发手册(嵩山终极版)
9.回复"总结"获取Java后端面试经验总结PDF版
10.回复"Redis"获取Redis命令手册,和Redis专项面试习题(PDF)
11.回复"并发导图"获取Java并发编程思维导图(xmind终极版)
另:点击【我的福利】有更多惊喜哦。