垃圾回收 笔记记录

  • 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. 垃圾回收调优

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87551.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87551.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/87551.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《二叉搜索树》

引言&#xff1a; 上次我们结束了类和对象的收尾&#xff0c;之后我们就要学习一些高级的数据结构&#xff0c;今天我们先来看一个数据结构-- 二叉搜索树。 一&#xff1a; 二叉搜索树的概念(性质) 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是…

【Redis】Sentinel哨兵

&#x1f6e1;️ 深入理解 Redis Sentinel&#xff1a;高可用架构的守护者 在实际开发中&#xff0c;我们常用 Redis 构建缓存系统或数据中间件。然而&#xff0c;主从复制虽然能实现数据同步&#xff0c;但无法自动故障转移&#xff08;failover&#xff09;&#xff0c;这就…

Shell脚本应用及实战演练

文章目录 一、Shell脚本语言的基本结构1、Shell脚本的用途&#xff1a;2、 Shell脚本基本结构&#xff1a;3、 创建Shell脚本过程4、 脚本注释规范 二、Shell脚本语言的变量用法详解位置与预定义变量 三、 Shell字符串详解1、Shell字符串拼接2、Shell字符串截取3、 Shell的格式…

软件工程瀑布模型学习指南

软件工程瀑布模型学习指南 一、瀑布模型核心概念 1.1 定义与特点 瀑布模型是一种经典的软件开发流程,将项目划分为顺序性的阶段,每个阶段有明确的输入和输出,如同瀑布流水般单向推进。其特点包括: 阶段间具有明确的顺序性和依赖性强调文档驱动和阶段评审适合需求明确、稳…

获取gitlab上项目分支版本(二)

获取gitlab上项目分支版本_gitlab代码分支版本在哪-CSDN博客 原先写过一版&#xff0c;但是这次想更新一下项目的分支信息时&#xff0c;提示我 git服务器上的Python版本是2.7.3&#xff0c;这个错误表明当前Python环境中没有安装requests库&#xff0c;服务器也没有连接外网&…

主流防火墙策略绕过漏洞的修复方案与加固实践

主流防火墙策略绕过漏洞的修复方案与加固实践 流量关键点分析&#xff08;攻击手法&#xff09; 攻击者通过精心构造的TCP序列号攻击和恶意标志组合绕过防火墙DPI检测&#xff0c;核心手法如下&#xff1a; TCP连接建立&#xff08;正常握手&#xff09; 1049&#xff1a;客户…

泛微OAe9-后端二开常见数据库操作

泛微OAe9-后端二开常见数据库操作 文章目录 泛微OAe9-后端二开常见数据库操作一、RecordSet1 RecordSet 操作OA本身的表2 RecordSet 操作OA 本身的存储过程 二、RecordSetTrans三、RecordSetDataSource四、原生 jdbc 一、RecordSet RecordSet 适用于操作 OA 自己的库。OA 数据库…

【数据分析八:hypothesis testing】假设检验

本节我们讲述假设检验和抽样方法 有关假设检验的详细内容&#xff0c;可以参考我以往的博客 概率论与数理统计总复习_概率论与数理统计复习-CSDN博客文章浏览阅读1.5k次&#xff0c;点赞33次&#xff0c;收藏23次。中科大使用的教辅《概率论和数理统计》&#xff0c;带大家复…

AI免费工具:promptpilot、今天学点啥、中英文翻译

promptpilot 激发模型潜能&#xff0c;轻松优化 Prompt https://promptpilot.volcengine.com/startup 今天学点啥 https://metaso.cn/study 能生成网页和语音播报 中英文翻译 沉浸式翻译&#xff0c;浏览器插件&#xff0c;ai翻译

计算机网络学习笔记:TCP三报文握手、四报文挥手

文章目录 前言一、TCP三报文握手二、TCP四报文挥手三、TCP保活计时器 前言 TCP通信&#xff0c;通常需要经历三个阶段&#xff1a;三报文握手->发送&#xff0c;接收数据->四报文挥手。 一、TCP三报文握手 三报文握手处于TCP的连接建立阶段&#xff0c;主要解决了以下的…

kafka部署和基本操作

一、部署kafka 解压 tar xzvf kafka_2.12-3.9.1.tgz tar -zxf kafka_2.12-3.9.1.tgz 1.修改config/server.properties # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # …

Bootstrap 5学习教程,从入门到精通,Bootstrap 5 导航语法知识点及案例代码(17)

Bootstrap 5 导航语法知识点及案例代码 Bootstrap 5 提供了强大的导航组件&#xff0c;帮助开发者快速构建响应式且美观的导航栏。 一、Bootstrap 5 导航组件概述 Bootstrap 5 提供了多种导航组件&#xff0c;主要包括&#xff1a; 导航栏&#xff08;Navbar&#xff09;&am…

清除 docker 无用的 镜像/容器

清除 docker 无用的 镜像/容器 删除 <none> 的 docker 镜像 使用以下命令删除所有 的 Docker 镜像&#xff08;即悬空镜像 / dangling images&#xff09;&#xff1a; docker image prune -f这会自动删除所有没有 tag 的镜像&#xff08;&#xff09;&#xff0c;不会…

使用Charles抓包工具提升API调试与性能优化效率

在软件开发过程中&#xff0c;网络请求调试和性能优化往往成为开发者遇到的挑战&#xff0c;尤其是在进行API接口调试时。开发者需要确保网络请求的正确性、响应时间以及系统的整体性能。然而&#xff0c;传统的调试方法常常无法提供足够的细节来深入分析问题&#xff0c;进而影…

如何协调各项目关键节点的冲突与依赖

在多项目并行的环境下&#xff0c;关键节点间的冲突与依赖是导致项目延期、资源浪费和沟通误解的主要根源。要高效协调此类问题&#xff0c;企业应重点从建立透明的进度依赖图、使用项目管理工具对齐节点、推动跨部门协同机制入手。其中&#xff0c;通过Gantt图或关键路径法实现…

mongodb单节点改副本集模式

前一阵将三节点的副本集改成了单节点&#xff0c;但后面业务代码出现问题&#xff1a;无法使用事务&#xff0c;因为事务只有在副本集上能用&#xff0c;单节点无法使用&#xff0c;故需要改回副本集模式&#xff0c;而我目前仅有一台服务器&#xff0c;所以考虑在一台服务器上…

Android 修改了页面的xml布局,使用了databinding,这时候编译时需要用到apt吗

deepseek回答&#xff1a; 在 Android 开发中使用 DataBinding 时&#xff0c;不需要显式使用 apt&#xff08;Annotation Processing Tool&#xff09;。以下是详细说明&#xff1a; 1. DataBinding 的编译机制 DataBinding 是 Android Gradle 插件原生支持的功能&#xff…

服务器如何从http升级到https(nginx)

1.证书申请 可以到阿里云或者华为云去申请证书&#xff0c;申请完下载证书是个压缩包&#xff0c;然后解压 可以到到几个文件夹&#xff0c;找到 .Nginx 文件夹打开 会有两个文件&#xff0c;将这两个文件上传至nginx/conf/cert文件夹下&#xff08;cert需要手…

6.19_JAVA_微服务

1、跑后端的时候要把数据库跑起来&#xff0c;否则会报错。 2、predicate断言&#xff1a; 预言&#xff1a;predict 3、gateway&#xff1a;出路口 4、API&#xff1a;List.of("a", "b", "c");把abc编程一个集合。 5、 6、shortcutFieldOrd…

Linux 基础命令:`ls`、`cd`、`du` 快速入门

在 Linux 系统中&#xff0c;ls、cd 和 du 是日常操作中最常用的三个命令。掌握它们能大幅提升文件管理效率。 1. ls&#xff1a;查看目录内容 用途&#xff1a;列出当前或指定目录下的文件和子目录。 常用命令&#xff1a; ls -l # 详细列表&#xff08;权限、大…