【实战JVM】-基础篇-04-自动垃圾回收

【实战JVM】-基础篇-04-自动垃圾回收

  • 自动垃圾回收
  • 1 多语言内存管理
    • 1.1 C/C++的内存管理
    • 1.2 Java的内存管理
    • 1.3 自动与手动对比
    • 1.4 应用场景
  • 2 方法区的回收
    • 2.1 回收条件
  • 3 堆回收
    • 3.1 判断是否被引用
      • 3.1.1 引用计数法
      • 3.1.2 可达性分析算法
        • 3.1.2.1 GC Root
        • 3.1.2.2 监视GC Root
        • 3.1.2.3 总结
    • 3.2 五种对象引用
      • 3.2.1 软引用
        • 3.2.1.1 软引用使用
        • 3.2.1.2 软引用回收
        • 3.2.1.3 软引用使用场景-缓存
      • 3.2.2 弱引用
      • 3.2.4 虚引用和终结器引用
    • 3.3 垃圾回收算法
      • 3.3.1 垃圾回收算法标准
      • 3.3.2 标记清除算法
      • 3.3.3 复制算法
      • 3.3.4 标记整理算法
      • 3.3.5 分代GC
        • 3.3.5.1 分代垃圾回收算法
    • 3.4 垃圾回收器
      • 3.4.1 Serial-Serial Old
      • 3.4.2 ParNew-CMS
      • 3.4.3 Parallel Scavenge-Parallel Old
      • 3.4.4 G1
        • 3.4.4.1 内存结构
        • 3.4.4.2 回收策略
        • 3.4.4.3 使用G1
      • 3.4.5 选择组合策略


自动垃圾回收

1 多语言内存管理

1.1 C/C++的内存管理

在这里插入图片描述

1.2 Java的内存管理

在这里插入图片描述

1.3 自动与手动对比

在这里插入图片描述

1.4 应用场景

在这里插入图片描述

2 方法区的回收

在这里插入图片描述

2.1 回收条件

在这里插入图片描述

3 堆回收

在这里插入图片描述

在这里插入图片描述

3.1 判断是否被引用

3.1.1 引用计数法

在这里插入图片描述

C++智能指针就采用引用计数法,但是存在缺点:

  • 每次引用和取消引用都需要维护计数器,对系统性能会有一定的影响。
  • 存在循环引用问题,所谓循环引用就是当A引用B,B同时引用A时会出现对象无法回收的问题。

在这里插入图片描述

查看垃圾回收信息,采用-verbose:gc参数,但是java并没有采用引用计数法。使用的是可达性分析算法。

3.1.2 可达性分析算法

在这里插入图片描述

注:GC Root对象不可被回收

3.1.2.1 GC Root

在这里插入图片描述

  1. 线程Thread对象

    包括主线程,子线程等等。

  2. java.lang.Class对象

    系统类加载器加载的java.lang.*中的Class对象,其中包括sun.misc.Launcher类,再由sun.misc.Launcher类加载扩展类和应用程序类加载器。
    在这里插入图片描述

  3. 监视器对象

    在这里插入图片描述

3.1.2.2 监视GC Root
public class ReferenceCounting {private static A a2=null;public static void main(String[] args) throws IOException {A a1=new A();B b1=new B();a1.b=b1;b1.a=a1;a2=a1;System.in.read();}
}
class B {public A a;
}
class A {public B b;
}

启动arthas

java -Dfile.encoding=UTF-8 -jar arthas-boot.jar

进入ReferenceCounting,对内存进行快照

heapdump "D:\File\StudyJavaFile\JavaStudy\JVM\low\day03\resource\test2.hprof"

先把环境变量的jdk设为17再启动memoryanalyzer

在这里插入图片描述

打开刚刚的内存快照,canel取消引导

在这里插入图片描述

在这里插入图片描述

选择GC Root

在这里插入图片描述

可以看到成员变量实际在堆中存放的是直接引用

在这里插入图片描述

所有的局部变量和成员变量已经看过了,我们来找静态变量a2

private static A a2=null;
public static void main(String[] args) throws IOException {A a1=new A();B b1=new B();a1.b=b1;b1.a=a1;a2=a1;System.in.read();}

静态变量通过应用程序加载器加载到堆中,A类应该还有个应用程序类的加载器的GCroot指向A,我们通过path to gcroot来找引用

在这里插入图片描述

在这里插入图片描述

我们可以看到有三个引用,亦可以看到应用程序加载器的父类都有哪些。

在这里插入图片描述

3.1.2.3 总结

在这里插入图片描述

3.2 五种对象引用

在这里插入图片描述

3.2.1 软引用

在这里插入图片描述

使用软引用必须创建两个对象:

  1. 软引用自身SoftReference对象
  2. 在软引用自身SoftReference对象中创建第二个对象A,才是程序真正使用的对象

在这里插入图片描述

3.2.1.1 软引用使用
public class SoftReferenceDemo2 {public static void main(String[] args) throws IOException {byte[] bytes = new byte[1024 * 1024 * 100];SoftReference<byte[]> softReference = new SoftReference<byte[]>(bytes);bytes = null;System.out.println(softReference.get());byte[] bytes2 = new byte[1024 * 1024 * 100];System.out.println(softReference.get());

//        byte[] bytes3 = new byte[1024 * 1024 * 100];
//        softReference = null;
        System.gc();

        System.in.read();}
}

设置最大堆内存-Xmx200m,启动,总共200M实际能用不到200M,自然第一个放进去第二个放不进去,然后软引用就被释放回收了,打印null

[B@7ba4f24f
null

设置最大堆内存-Xmx400m,都能发进去,并且指向同一个软引用空间

[B@7ba4f24f
[B@7ba4f24f

修改回200m,添加

byte[] bytes3 = new byte[1024 * 1024 * 100];

已经把软引用释放了,就不能添加了,自然报outofmemory

[B@7ba4f24f
null
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat chapter04.soft.SoftReferenceDemo2.main(SoftReferenceDemo2.java:20)
3.2.1.2 软引用回收

在这里插入图片描述

public class SoftReferenceDemo3 {public static void main(String[] args) throws IOException {ArrayList<SoftReference> softReferences = new ArrayList<>();ReferenceQueue<byte[]> queues = new ReferenceQueue<byte[]>();for (int i = 0; i < 10; i++) {byte[] bytes = new byte[1024 * 1024 * 100];SoftReference studentRef = new SoftReference<byte[]>(bytes,queues);softReferences.add(studentRef);}SoftReference<byte[]> ref = null;int count = 0;while ((ref = (SoftReference<byte[]>) queues.poll()) != null) {count++;}System.out.println(count);}
}

设置堆内存200M,只够存一个,后一个盒子把前一个盒子覆盖了,并且把前一个盒子放进queue中。所以最后一个存在,没有被回收,因此输出9

3.2.1.3 软引用使用场景-缓存

在这里插入图片描述

在这里插入图片描述

通过在软引用对象中添加一个属性 _key来方便后面的清理HashMap,如果内存不足,软引用自动清除,然后再根据引用队列中queue中存在的软引用对象,再通过软引用的属性 _key来清理HashMap完成闭环的清理缓存的操作。

public class StudentCache {private static StudentCache cache = new StudentCache();public static void main(String[] args) {for (int i = 0; ; i++) {StudentCache.getInstance().cacheStudent(new Student(i, String.valueOf(i)));}}private Map<Integer, StudentRef> StudentRefs;// 用于Cache内容的存储private ReferenceQueue<Student> q;// 垃圾Reference的队列// 继承SoftReference,使得每一个实例都具有可识别的标识。// 并且该标识与其在HashMap内的key相同。private class StudentRef extends SoftReference<Student> {private Integer _key = null;public StudentRef(Student em, ReferenceQueue<Student> q) {super(em, q);_key = em.getId();}}// 构建一个缓存器实例private StudentCache() {StudentRefs = new HashMap<Integer, StudentRef>();q = new ReferenceQueue<Student>();}// 取得缓存器实例public static StudentCache getInstance() {return cache;}// 以软引用的方式对一个Student对象的实例进行引用并保存该引用private void cacheStudent(Student em) {cleanCache();// 清除垃圾引用StudentRef ref = new StudentRef(em, q);StudentRefs.put(em.getId(), ref);System.out.println(StudentRefs.size());}// 依据所指定的ID号,重新获取相应Student对象的实例public Student getStudent(Integer id) {Student em = null;
// 缓存中是否有该Student实例的软引用,如果有,从软引用中取得。if (StudentRefs.containsKey(id)) {StudentRef ref = StudentRefs.get(id);em = ref.get();}
// 如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,
// 并保存对这个新建实例的软引用if (em == null) {em = new Student(id, String.valueOf(id));System.out.println("Retrieve From StudentInfoCenter. ID=" + id);this.cacheStudent(em);}return em;}// 清除那些所软引用的Student对象已经被回收的StudentRef对象private void cleanCache() {StudentRef ref = null;while ((ref = (StudentRef) q.poll()) != null) {StudentRefs.remove(ref._key);}}//    // 清除Cache内的全部内容
//    public void clearCache() {
//        cleanCache();
//        StudentRefs.clear();
//        //System.gc();
//        //System.runFinalization();
//    }
}class Student {int id;String name;public Student(int id, String name) {this.id = id;this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

3.2.2 弱引用

在这里插入图片描述

public class WeakReferenceDemo2 {public static void main(String[] args) throws IOException {byte[] bytes = new byte[1024 * 1024 * 100];WeakReference<byte[]> weakReference = new WeakReference<byte[]>(bytes);bytes = null;System.out.println(weakReference.get());System.gc();System.out.println(weakReference.get());}
}

打印,不管有没有数据,全部回收

[B@7ba4f24f
null

3.2.4 虚引用和终结器引用

在这里插入图片描述

3.3 垃圾回收算法

在这里插入图片描述

释放不再存活对象的内存,使得程序能再次利用这部分空间。

3.3.1 垃圾回收算法标准

在这里插入图片描述

  • 最大吞吐量
  • 最大暂停时间
  • 堆使用效率

3.3.2 标记清除算法

在这里插入图片描述

  • 优点:实现简单,只需要在一阶段给每个对象维护一个标志位,第二阶段删除对象即可。
  • 缺点:碎片化问题(外部碎片),分配速度慢(扫描空闲链表,速度慢)

3.3.3 复制算法

在这里插入图片描述

在这里插入图片描述

3.3.4 标记整理算法

在这里插入图片描述

在这里插入图片描述

3.3.5 分代GC

在这里插入图片描述

在jdk8中,添加-XX:+UserSerialGC参数使用分代回收的垃圾回收器,运行程序

在arthas中使用memory命令查看内存,显示三个区域内存情况。

在这里插入图片描述

public class GcDemo0 {public static void main(String[] args) throws IOException {List<Object> list = new ArrayList<>();int count = 0;while (true){System.in.read();System.out.println(++count);//每次添加1m的数据list.add(new byte[1024 * 1024 * 1]);}}
}

添加参数 -XX:+UseSerialGC -Xms60m -Xmn20m -Xmx60m -XX:SurvivorRatio=3 -XX:+PrintGCDetails

应当是总共60M,老年代40M,新生代20M,新生代中,伊甸园12M,S0,S1各4M,满足SurvivorRatio=3的3:1:1

在这里插入图片描述

3.3.5.1 分代垃圾回收算法

在这里插入图片描述

在复制算法中,S0和S1会发生互换,第一次MinorGC全放到To中,然后To和From交换名字。

在这里插入图片描述

在这里插入图片描述

FullGC对新生代和老年代一起回收

3.4 垃圾回收器

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.4.1 Serial-Serial Old

新生代采用复制算法,老年代采用标记整理算法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.4.2 ParNew-CMS

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.4.3 Parallel Scavenge-Parallel Old

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.4.4 G1

在这里插入图片描述

3.4.4.1 内存结构

在这里插入图片描述

在这里插入图片描述

3.4.4.2 回收策略

在这里插入图片描述

在这里插入图片描述

年轻代选择的复制算法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3.4.4.3 使用G1

在这里插入图片描述

3.4.5 选择组合策略

在这里插入图片描述

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

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

相关文章

基于ERNIE Bot SDK开发智趣灯谜会游戏

项目背景 猜灯谜是中国传统节日元宵节中一种深受人们喜爱的民间游戏&#xff0c;它集趣味性、知识性和艺术性于一体&#xff0c;是中华文化的重要组成部分。猜灯谜&#xff0c;顾名思义&#xff0c;就是通过解读谜面来猜测谜底&#xff0c;谜底通常是各种物品、现象或概念。 猜…

智能视频监控技术为游泳馆安全护航,助力安全管理新升级

随着社会的进步和科技的发展&#xff0c;视频监控技术在各行各业的应用越来越广泛。游泳馆作为公共场所&#xff0c;每天都会有大量的游泳者进出。在这样的环境中&#xff0c;有时难免会发生一些意外事故&#xff0c;如溺水、摔倒等。因此&#xff0c;视频监控建设的必要性尤为…

《MySQL怎样运行的》-从一条记录说起-InnoDB记录存储结构

我们都知道MySQL是用来存储数据的&#xff0c;那你有没有的疑问&#xff0c;他是怎么存储的&#xff0c;它实际上是在使用储存引擎&#xff0c;那如果有人问你MySQL的储存引擎有哪些你该怎么说呢&#xff0c;主要是有InnoDB&#xff0c;MyISAM还有MEMORY&#xff0c;后面两种在…

HiWoo Box工业网关

在科技飞速发展的今天&#xff0c;工业领域正迎来智能化变革。在这场变革中&#xff0c;工业网关作为连接工业设备与远程控制中心的桥梁&#xff0c;发挥着至关重要的作用。HiWoo Box网关凭借其卓越的性能和广泛的应用场景&#xff0c;为工业领域带来了全新的智慧化解决方案。 …

大模型主流 RAG 框架TOP10

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 总结链接…

中心入侵渗透

问题1. windows登录的明文密码&#xff0c;存储过程是怎么样的&#xff1f;密文存在哪个文件下&#xff1f;该文件是否可以打开&#xff0c;并且查看到密文&#xff1f; 回答&#xff1a; Windows登录的明文密码的存储过程是&#xff1a; 当用户尝试登录Windows时&#xff0…

瓦罗兰特国际服怎么注册账号 瓦罗兰特 无畏契约账号注册教程

瓦罗兰特国际服怎么注册账号 瓦罗兰特 无畏契约账号注册教程 瓦罗兰特作为拳头游戏开发的一款多人竞技第一人称射击游戏&#xff0c;自从2020年发布之后&#xff0c;热度持续升高&#xff0c;游戏采用5V5竞技模式&#xff0c;采用了传统FPS中游戏的类型&#xff0c;玩家们分为…

【软考】下篇 第19章 大数据架构设计理论与实践

目录 大数据处理系统架构特征Lambda架构Lambda架构介绍Lambda架构实现Lambda架构优缺点Lambda架构与其他架构模式对比 Kappa架构Kappa架构介绍Kappa架构实现Kappa架构优缺点 常见Kappa架构变形&#xff08;Kappa、混合分析系统&#xff09;Kappa架构混合分析系统的Kappa架构 La…

Golang协程和通道

文章目录 协程&#xff08;goroutine&#xff09;基本介绍GMP模型协程间共享变量 通道&#xff08;channel&#xff09;基本介绍channel的定义方式channel的读写channel的关闭channel的遍历方式只读/只写channelchannel最佳案例select语句 协程&#xff08;goroutine&#xff0…

撤销最近一次的提交,使用git revert 和 git reset的区别

文章目录 工作区 暂存区 本地仓库 远程仓库需求&#xff1a;已推送到远程仓库&#xff0c;想要撤销操作git revert &#xff08;添加新的提交来“反做”之前的更改&#xff0c;云端会残留上次的提交记录&#xff09;git reset&#xff08;相当于覆盖上次的提交&#xff09;1.--…

Maven高级详解

文章目录 一、分模块开发与设计分模块开发的意义模块拆分原则 分模块开发(模块拆分)创建Maven模块书写模块代码通过maven指令安装模块到本地仓库(install指令) 二、依赖管理依赖传递可选依赖排除依赖可选依赖和排除依赖的区别 三、聚合与继承聚合工程聚合工程开发创建Maven模块…

老师如何在线发布期末考试成绩查询?

在这个数字化时代&#xff0c;教育领域也迎来了翻天覆地的变化。传统的纸质成绩查询方式已经逐渐被在线成绩查询所替代。如何高效、便捷地进行在线期末考试成绩查询&#xff1f; 成绩的录入与上传。教师需要将学生的考试成绩准确无误地录入系统。这一步骤需要细心和耐心&#x…

阻塞、非阻塞、同步与异步IO的区别

IO读取数据的过程 如图所示&#xff0c;进程读取数据的过程主要分为两个步骤 1.内核将数据准备好到内核缓冲区 2.内核将数据拷贝到用户态 在上述这两个过程里&#xff0c;进程首先和内核打交道&#xff0c;之后内核再和硬件&#xff08;如网卡&#xff09;打交道 阻塞IO 如图所…

鹏哥C语言复习——调试

目录 什么是调试&#xff1f; Debug和Release&#xff1a; 调试方法&#xff1a; 环境准备&#xff1a; 调试快捷键介绍&#xff1a; 调试快捷键注意事项&#xff1a; 监视与内存查看&#xff1a; 数组元素的监视&#xff1a; 编译常见错误归类&#xff1a; 编译型错…

【前端学习笔记】HTML基础

HTML 一、HTML介绍1.HTML概念2.文档声明3.字符编码4. HTML标签5. HTML属性 二、标签1.meta标签2.语义标签3.布局标签4.列表5.超链接6.图片7.字符实体8.内联格式9.HTML 表格10.HTML 表单 三、HTML5新特性1. 本地存储2. Cookie3. 语义化标签4.多媒体元素5.表单增强6.Canvas7.SVG …

使用VUE3+TS+elementplus创建一个增加按钮

一、前言 在上一篇文章中分享了创建table的过程&#xff0c;详见&#xff08;VUE3TSelementplus创建table&#xff0c;纯前端的table&#xff09;&#xff0c;本文在创建好的table的基础上&#xff0c;再创建一个增加按钮。 二、程序展示 1、前面创建table的程序 <templ…

js的学习

什么是JavaScript? JavaScript(简称:JS)是一门跨平台、面向对象的脚本语言。是用来控制网页行为的&#xff0c;”它能使网页可交互。 JavaScript 和Java 是完全不同的语言&#xff0c;不论是概念还是设计。但是基础语法类似。 JavaScript在1995 年由 Brendan Eich 发明&#x…

Matlab-熵权法

文章目录 熵权法一、模型简介二、例题1. 数据标准化2.指标的熵值和变异程度3.权重与评分4.代码实现 熵权法 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多…

英特尔LLM技术挑战记录

英特尔技术介绍&#xff1a; Flash Attention Flash Attention 是一种高效的注意力机制实现&#xff0c;旨在优化大规模 Transformer 模型中的自注意力计算。在深度学习和自然语言处理领域&#xff0c;自注意力是 Transformer 架构的核心组件&#xff0c;用于模型中不同输入元…

骆驼大赛

目录 一&#xff0c;主版图 二&#xff0c;骰子 三&#xff0c;初始设置 四&#xff0c;核心规则 五&#xff0c;结算 这是适合5-8人玩的一个概率推理类的回合制桌游。 一&#xff0c;主版图 赛道由16个格子组成&#xff0c;编号为1-16。 一共7个骆驼&#xff0c;其中正…