在 JDK.1.2
之后,Java
对引用的概念进行了扩充,将引用分为了:
- 强引用
(Strong Reference)
- 软引用
(Soft Reference)
- 弱引用
(Weak Reference)
- 虚引用
(Phantom Reference)
4 种,这 4 种引用的强度依次减弱。不同的引用在垃圾回收中体现也是不一样~
M
我们先创建一个M对象,后面为了方便的感受GC的情况。
1 | package com.cyblogs.java.learning.C001_ReferenceType; |
finalize
函数是对象在gc
的时候,一定会调用该方法。我们重写一下该方法并且打印一行日志。
强引用
只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM
也会直接抛出OutOfMemoryError
,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null
,这样一来,JVM
就可以适时的回收对象了。
1 | package com.cyblogs.java.learning.C001_ReferenceType; |
控制台日志输出:
1 | Connected to the target VM, address: '127.0.0.1:53621', transport: 'socket' |
软引用
软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。
1 | package com.cyblogs.java.learning.C001_ReferenceType; |
因为它是在内存不足的时候才会触发,所以我们在跑之前需要设置一下最大堆。
1 | -Xmx20M |
控制台日志输出:
1 | Connected to the target VM, address: '127.0.0.1:54335', transport: 'socket' |
你会发现就算我们gc
了,后面还是会get
得到,因为空间还足够。当后面byte[] b
再继续申请空间的时候,发现空间不足了,这个时候就会触发gc
动作,把软引用的部分清除掉。
弱引用
弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。
1 | package com.cyblogs.java.learning.C001_ReferenceType; |
控制台日志输出:
1 | Connected to the target VM, address: '127.0.0.1:55151', transport: 'socket' |
我们看一下ThreadLocal
的set
方法:
1 | /** |
为什么Entry
要使用弱引用?
若是强引用,即使
tl=null
,但是key
的引用还是指向ThreadLocal
。所以内存会泄露~而弱引用不会但是还会有内存泄露的问题,
ThreadLocal
被回收。key
的值变成了null
,则导致value
的值再也无法被访问到,因此依然存在内存泄露问题。
虚引用
虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收,在 JDK1.2 之后,用 PhantomReference 类来表示,通过查看这个类的源码,发现它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。
1 | package com.cyblogs.java.learning.C001_ReferenceType; |
在零拷贝中就会使用到虚引用,但我们又无法去操作对外的内存。因为太弱了,我们也无法感知到~ 这里就需要利用到ReferenceQueue
。
参考地址
如果大家喜欢我的文章,可以关注个人订阅号。欢迎随时留言、交流。如果想加入微信群的话一起讨论的话,请加管理员简栈文化-小助手(lastpass4u),他会拉你们进群。