-
引用计数法:为每个对象添加一个引用计数器,每当有一个引用指向它时,计数器就加1,当引用失效时,计数器就减1,当计数器为0时,则认为该对象可以被回收(目前在Java中已经弃用这种方式了)。
-
可达性分析算法:从一个被称为 GC Roots 的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用。
JDK1.2 之前,一个对象只有“已被引用”和"未被引用"两种状态,这将无法描述某些特殊情况下的对象,比如,当内存充足时需要保留,而内存紧张时才需要被抛弃的一类对象。
=====================================================================
所以在 JDK.1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。
Java中默认声明的就是强引用,比如:
Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收
obj = null; //手动置null
复制代码
只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了
软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。
在 JDK1.2 之后,用java.lang.ref.SoftReference类来表示软引用。
下面以一个例子来进一步说明强引用和软引用的区别:
在运行下面的Java代码之前,需要先配置参数 -Xms2M -Xmx3M,将 JVM 的初始内存设为2M,最大可用内存为 3M。
首先先来测试一下强引用,在限制了 JVM 内存的前提下,下面的代码运行正常
public class TestOOM {
public static void main(String[] args) {
testStrongReference();
}
private static void testStrongReference() {
// 当 new byte为 1M 时,程序运行正常
byte[] buff = new byte[1024 * 1024 * 1];
}
}
复制代码
但是如果我们将
byte[] buff = new byte[1024 * 1024 * 1];
复制代码
替换为创建一个大小为 2M 的字节数组
byte[] buff = new byte[1024 * 1024 * 2];
复制代码
则内存不够使用,程序直接报错,强引用并不会被回收
接着来看一下软引用会有什么不一样,在下面的示例中连续创建了 10 个大小为 1M 的字节数组,并赋值给了软引用,然后循环遍历将这些对象打印出来。
public class TestOOM {
private static List list = new ArrayList<>();
public static void main(String[] args) {
testSoftReference();
}
private static void testSoftReference() {
for (int i = 0; i < 10; i++) {
byte[] buff = new byte[1024 * 1024];
SoftReference<byte[]> sr = new SoftReference<>(buff);
list.add(sr);
}
System.gc(); //主动通知垃圾回收
for(int i=0; i < list.size(); i++){
Object obj = ((SoftReference) list.get(i)).get();
System.out.println(obj);
}
}
}
复制代码
打印结果:
我们发现无论循环创建多少个软引用对象,打印结果总是只有最后一个对象被保留,其他的obj全都被置空回收了。
这里就说明了在内存不足的情况下,软引用将会被自动回收。
值得注意的一点 , 即使有 byte[] buff 引用指向对象, 且 buff 是一个strong reference, 但是 SoftReference sr 指向的对象仍然被回收了,这是因为Java的编译器发现了在之后的代码中, buff 已经没有被使用了, 所以自动进行了优化。
如果我们将上面示例稍微修改一下:
private static void testSoftReference() {
byte[] buff = null;
for (int i = 0; i < 10; i++) {
buff = new byte[1024 * 1024];
SoftReference<byte[]> sr = new SoftReference<>(buff);
list.add(sr);
}
System.gc(); //主动通知垃圾回收
for(int i=0; i < list.size(); i++){
Object obj = ((SoftReference) list.get(i)).get();
System.out.println(obj);
}
System.out.println("buff: " + buff.toString());
}
复制代码
则 buff 会因为强引用的存在,而无法被垃圾回收,从而抛出OOM的错误。
如果一个对象惟一剩下的引用是软引用,那么该对象是软可及的(softly reachable)。垃圾收集器并不像其收集弱可及的对象一样尽量地收集软可及的对象,相反,它只在真正 “需要” 内存时才收集软可及的对象。
弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。在 JDK1.2 之后,用 java.lang.ref.WeakReference 来表示弱引用。
我们以与软引用同样的方式来测试一下弱引用:
private static void testWeakReference() {
for (int i = 0; i < 10; i++) {
byte[] buff = new byte[1024 * 1024];
WeakReference<byte[]> sr = new WeakReference<>(buff);
list.add(sr);
}
System.gc(); //主动通知垃圾回收
for(int i=0; i < list.size(); i++){
Object obj = ((WeakReference) list.get(i)).get();
System.out.println(obj);
}
}
复制代码
打印结果:
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
-1715725726528)]
[外链图片转存中…(img-u6mefO86-1715725726529)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!