您的位置:首页 > 娱乐 > 八卦 > 北京海淀区网络科技有限公司_拜年视频制作软件_厉害的seo顾问_可以发外链的网站整理

北京海淀区网络科技有限公司_拜年视频制作软件_厉害的seo顾问_可以发外链的网站整理

2025/7/15 2:33:30 来源:https://blog.csdn.net/qq_43520227/article/details/148716460  浏览:    关键词:北京海淀区网络科技有限公司_拜年视频制作软件_厉害的seo顾问_可以发外链的网站整理
北京海淀区网络科技有限公司_拜年视频制作软件_厉害的seo顾问_可以发外链的网站整理

垃圾回收 笔记记录

  • 1. 如何判断对象可以回收
    • 1.1 引用计数法
      • 1.1.1 缺点
    • 1.2 可达性分析算法
      • 1.2.1 可达分析、根对象
      • 1.2.2 优缺点
    • 1.3 四种引用(强软弱虚)
      • 1.3.1 软引用的实际使用案例
      • 1.3.2 软引用-引用队列
      • 1.3.3 弱引用的实际使用案例
  • 2. 垃圾回收算法
    • 2.1 标记清除算法
    • 2.2 标记整理
    • 2.3 复制
  • 3. 分代垃圾回收
  • 4. 垃圾回收器
    • 4.1 吞吐量优先
    • 4.2 响应时间优先
  • 5. 垃圾回收调优

1. 如何判断对象可以回收

下面介绍一些判断对象是否可以被回收的算法。

1.1 引用计数法

基本原理

  1. 每个对象关联一个计数器(整数),记录当前有多少引用指向它。
  2. 引用增加时(如被变量赋值、被其他对象引用),计数器+1。
  3. 引用减少时(如变量离开作用域、被显式置为null),计数器-1。
  4. 当计数器归零,说明对象不再被任何引用指向,立即回收其内存。

1.1.1 缺点

引用计数法虽然简单,但存在一个致命问题:无法解决循环引用。例如:

class A {B b;
}class B {A a;
}public class Main {public static void main(String[] args) {A a = new A(); // A 的引用计数 = 1B b = new B(); // B 的引用计数 = 1a.b = b; // B 的引用计数 = 2b.a = a; // A 的引用计数 = 2a = null; // A 的引用计数 = 1b = null; // B 的引用计数 = 1// 此时 A 和 B 互相引用,引用计数都不为 0,但已经无法访问,造成内存泄漏!}
}

问题:

  1. 即使 a 和 b 已经不再被外部引用,但由于它们互相引用,引用计数仍然 > 0,导致无法回收,造成内存泄漏。
  2. Java 的解决方案:采用可达性分析(Reachability Analysis),从 GC Roots(如静态变量、活动线程栈变量等)出发,标记所有可达对象,未被标记的则回收。

1.2 可达性分析算法

  1. 可达性分析算法(Reachability Analysis)是 Java 垃圾回收(GC)的核心算法,用于判断对象是否存活。相比引用计数法,它能有效解决循环引用问题,是现代 JVM 采用的默认策略。
  2. 从一组「GC Roots」出发,遍历所有能被引用的对象,未被遍历到的即为垃圾。类似于“从树根出发,标记所有可达的树枝和树叶,剩下的就是需要清理的枯枝”。
  3. 在这里插入图片描述
  4. 肯定不能当成垃圾被回收的对象称为根对象

1.2.1 可达分析、根对象

  • Java虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象。
  • 扫描堆中的对象,看是否能够沿着GC Root对象为起点的引用链找到该对象,找不到,表示可以回收。
  • 哪些对象可以作为GC Root? 这里可以使用eclipse提供的MAT来找到
    在这里插入图片描述
    MAT中有一个功能就是找到当前快照中的GC Roots
    在这里插入图片描述
    GC Roots 构成:在这里插入图片描述

jps 找到当前运行类的进程id
再配合jmap -dump:format=b,live,file=1.bin 21384
dump就是把堆内存当前运行的状态转储成一个文件。
format表示转储文件的格式,b是二进制格式。
live会主动触发一次垃圾回收,我们关注一次回收后还存活的对象。
file=1.bin 表示存储的文件名称。
21384就是jps看到的进程id.

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/*** 通过Eclipse的MAT 查看哪些是GC Roots对象* */
public class Demo {public static void main(String[] args) throws IOException {List<Object> list=new ArrayList<>();list.add("a");list.add("b");System.out.println(1);System.in.read();list=null;System.out.println(2);System.in.read();System.out.println("end...");}
}

1.2.2 优缺点

这里是引用

1.3 四种引用(强软弱虚)

  1. 强引用:默认的引用类型,只要强引用存在,对象就不会被 GC 回收。即使内存不足(OOM),JVM 也不会回收强引用对象,而是抛出 OutOfMemoryError。 通对象创建(如 String s = “hello”),我们平时写代码new xx()都属于强引用。
  2. 软引用:当 内存不足时,GC 会回收软引用对象。适合实现 内存敏感的缓存(如图片缓存)。
  3. 弱引用:只要发生 GC,无论内存是否充足,弱引用对象都会被回收。比软引用更短暂,适合存储 非必须的元数据。
  4. 虚引用:无法通过虚引用获取对象(get() 始终返回 null)。
    唯一作用:对象被回收时收到系统通知(通过 ReferenceQueue)。
    必须与 ReferenceQueue 联合使用。
  5. 其实还有一种,终结器引用:是一种与对象生命周期相关的特殊机制,它通过 finalize() 方法在对象被垃圾回收(GC)前提供一次“临终拯救”机会。但因其设计缺陷,Java 9 开始已被标记为废弃(@Deprecated),并建议使用更安全的替代方案(如 Cleaner)。
    在这里插入图片描述

四种引用的对比在这里插入图片描述
在这里插入图片描述

1.3.1 软引用的实际使用案例

这里设置堆内存是20m Xmx20m,对于某些图片资源非核心业务,如果用强引用进行引用就会有可能导致内存溢出。这种不太重要的资源可以在内存紧张时将内存释放掉,这种场景就可以使用软引用。
下面代码演示放入20m的对象,发现堆内存不够直接OOM了,后面的例子使用软引用就不会OOM。
在这里插入图片描述

    private static final int _4MB=4*1024*1024;public static void main(String[] args) throws IOException {List<byte []> list=new ArrayList<>();for (int i=0;i<5;i++){list.add(new byte[_4MB]);}System.in.read();}

使用软引用:内存不足时被回收
在这里插入图片描述
前4个都被释放了,只有最后1个byte数组还在。在这里插入图片描述

    public static void soft(){// list -->SoftReference --> byte[]List<SoftReference<byte[]>> list=new ArrayList<>();for (int i=0;i<5;i++){SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);System.out.println(ref.get());list.add(ref);System.out.println(list.size());}System.out.println("循环结束:"+list.size());for (SoftReference<byte[]> softReference : list) {System.out.println(softReference.get());}}

1.3.2 软引用-引用队列

前面的演示我们发现,当使用软引用的时候,可能前4个byte数组已经被释放了,只保留了第5个在内存中。也就是最后遍历list的时候很多元素都是null了,对这些软引用对象,其实没必要保留在list中了。这种情况我们希望把软引用本身也做一个清理,既然释放了,就把引用也清除掉。因为软引用本身也要占用内存,尽管占用的相对较少。
如何清理无用的软引用呢,就需要用到引用队列。

    public static void soft() {List<SoftReference<byte[]>> list = new ArrayList<>();//引用队列ReferenceQueue<byte[]> queue = new ReferenceQueue<>();for (int i = 0; i < 5; i++) {//关联了引用队列,当软引用所关联的byte[]被回收时,那么软引用会被加入到引用队列queue中去。SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB], queue);System.out.println(ref.get());list.add(ref);System.out.println(list.size());}System.out.println("循环结束:" + list.size());//获取队列中的软引用Reference<? extends byte[]> poll = queue.poll();while (poll != null) {list.remove(poll);poll = queue.poll();}System.out.println("list中剩余的:===================>");for (SoftReference<byte[]> softReference : list) {System.out.println(softReference.get());}}

这时候看到list只有未被回收的byte数组。在这里插入图片描述

1.3.3 弱引用的实际使用案例

这里可以看到第10次可能是因为软弱引用本身也比较多了,发生了fullgc,前面几次没快超出堆内存时也会发发生了gc,所以又几个null值。这里是引用

    public static void weak() {List<WeakReference<byte[]>> list = new ArrayList<>();//引用队列ReferenceQueue<byte[]> queue = new ReferenceQueue<>();for (int i = 0; i < 10; i++) {WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB], queue);list.add(ref);for (WeakReference<byte[]> weakReference : list) {System.out.print(weakReference.get() + " ");}System.out.println();}}

2. 垃圾回收算法

2.1 标记清除算法

2.2 标记整理

2.3 复制

3. 分代垃圾回收

4. 垃圾回收器

4.1 吞吐量优先

4.2 响应时间优先

5. 垃圾回收调优

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com