JVM原理:JVM垃圾回收算法(通俗易懂)

目录

  • 前言
  • 正文
    • 垃圾标记算法
      • 引用类型
        • 强引用
        • 软引用
        • 弱引用
        • 虚引用
      • 引用计数法
        • 循环引用问题
      • 根可达性分析法
        • 虚拟机栈(栈帧的局部变量表)中的引用
        • 方法区中类静态属性引用
        • 方法区中常量引用
        • 本地方法栈(Native方法)引用
    • 垃圾回收算法
      • 标记清除算法
      • 复制算法
        • 复制算法和标记清除算法如何选择?
      • 标记整理算法
      • 分代收集算法
  • 总结

前言

为什么程序跑久了有时会变卡,如果你看过笔者的 《JVM运行时内存模型》那么应该知道用户线程在跑时会将new出来的对象放到虚拟机堆中,当堆满了之后会发生垃圾回收,而垃圾回收过程中会STW,也就是停止用户线程运行,这种在程序层面看来就是没反应,所以如果出现这种问题,我们就要想办法让STW的时间尽量的变短;

这分为几种情况,垃圾回收时间长或者垃圾回收的频率高;

垃圾回收时间长的情况?

可能是因为GC要扫描的区域比较大有,清理时间较长,或者说我们选择的垃圾回收器不适合当下情况

GC频率过高

可能有部分对象发生内存泄漏,导致无法回收,占用堆空间,此时的堆空间变小,满了就触发GC,频率自然高。也可能是年轻代和老年代空间分配不合理,空间过小导致频繁GC;

正文

认清原理,并接受原理,才能有效地做事情,所以我们要知道有哪些垃圾回收算法、哪些垃圾回收器,了解其特性,才可以帮忙我们进行程序优化。

垃圾标记算法

程序运行时,堆中存储了一堆对象,那垃圾回收器怎么知道哪些需要回收,不会发生误回收的情况呢?当一个实例对象有被引用时可以认为它是个活跃的状态,不进行回收。所以根据这个特性,可以添加一个标记专门记录被引用的次数,当次数不为0的就不进行垃圾回收,这种方式就是引用计数法。还可以在根节点挨个遍历,遍历到的对象进行标记,那些没遍历到的则被当作垃圾处理,这里的根节点可以简单理解为main方法里面开始的都是根,这种方式就是根可达性分析法;目前使用最多的是根可达性分析法;

引用类型

强引用

强引用我们平常用得最多,强引用在内存不足时,垃圾回收器不会进行回收,即使抛出OOM,因为该实例对象被引用,证明不是垃圾数据。

如:

Person person=new Person();

软引用

软引用在内存不足时(证明老年代满了,触发FULL GC),垃圾回收器会进行回收,所以垃圾标记算法在扫描标记时,判断如果引用为软引用,则把它当垃圾处理;

如:

Person person=new Person();

SoftReference<Person> sPerson=new SoftReference<>(new Persion());

弱引用

弱引用不管内存够不够时,这里内存够触发GC则证明年轻代满了触发YGC,内存不够则证明是老年代满了触发FULL GC,只要进行垃圾回收就会被当垃圾清除;

如:

Person person=new Person();

WeakReference<Person> sPerson=new WeakReference<>(new Persion());

虚引用

虚引用在垃圾回收时被清理,一般配合队列使用,在垃圾回收时会将其加入队列,此时队列可以拿到虚引用,但是虚引用指向的强引用Person已经被回收了,调用phantomReference.get()方法时获取不到实例对象;

 ReferenceQueue<Person> QUEUE = new RegferenceQueue<>();
 Person person=new Person();
 PhantomReference phantomReference = new PhantomReference(person, QUEUE);

引用计数法

我们在引用指向对象时就给该对象引用次数加1,在指引指向别的对象或变量销毁时将其-1,在垃圾回收器进行回收时,判断对象的引用标记数是否为0,如果为0则认为它是垃圾数据,对其进行回收;

优点:算法简单,判断搞笑

缺点:无法解决循环引用问题

循环引用问题

public class MyObject {
    public Object ref = null;
    public static void main(String[] args) {
        Person person1 = new Person();
        Person person2 = new Person();
        person1.friend = person2;
        person2.friend = person1;
        person1 = null;
        person2 = null;
    }
}

在这里插入图片描述

虽然person1对象和person2对象已经没有任何引用指向它们了,但是此时它们的引用标记数依旧不为0,垃圾回收器认为它们不是垃圾,导致空间无法得到释放;

在这里插入图片描述

根可达性分析法

根可达性法以GC ROOTS节点为起点,开始往下扫描,遍历属性引用关系来判断对象是否为可回收的垃圾对象;如果把ROOTS比喻成江河的源头,那么那些未跟源头相通的河或者内湖就可以理解为垃圾对象,三色标记法是比较常用的根可达性分析法;

在这里插入图片描述

那么,GC Roots 是什么呢?

虚拟机栈(栈帧的局部变量表)中的引用

public class Demo {
    public static void main(String[] args) {
        // 创建实例A
        // a1:就是虚拟机栈(栈帧的局部变量表)中引用
        A a1 = new A();
        
        // 当 a1 不再指向实例A的时候,实例A 将不可达
        a1 = null;
    }
}

当开启一个新线程时,会创建线程私有的虚拟机栈,栈帧中维护着局部变量表,线程执行方法中的变量会记录到局部变量表里面,所以可以把局部变量表的变量理解为GC Roots,往下遍历其引用链,在引用链上的都是可用对象;

方法区中类静态属性引用

public class Demo {
    // 创建实例A
    // a2:方法区中类静态属性引用
    public static A a2 = new A();

    public static void main(String[] args) {
        // 当 a2 不再指向实例A的时候,实例A 将不可达
        a2 = null;
    }
}

当属性被static修饰时,其变量会放到方法区中的静态变量区中,静态变量区的变量指向的引用可以看作GC ROOTS;

方法区中常量引用

public class Demo {
    // 创建实例A
    // a3:方法区中常量引用
    public static final A a3 = new A();

    public static void main(String[] args) {
        // 当 a3 不再指向实例A的时候,实例A 将不可达
        a3 = null;
    }
}

当使用final修饰后,其变量会存储到方法区中的常量池中,所以方法区中常量引用可以看作GC ROOTS;

本地方法栈(Native方法)引用

本地方法栈和虚拟机栈类型,也会维护局部变量表,当本地方法区引用了堆中的对象时,可以把其当作GC ROOTS;

垃圾回收算法

标记清除算法

标记清除法分为了标记和清除两个步骤,首先采用可达性分析法进行标记后,对被标记为垃圾的对象进行回收;

在这里插入图片描述

黑色为已经扫描过的,有被引用的对象,灰色代表待扫描对象,白色代表待垃圾回收对象;当垃圾回收完成后,此时的空间就变得很碎片化,如果此时需要存入一个对象,该对象占用3个格子的空间,那么第一行的两格空间就没法被利用到;所以碎片化太严重的情况下,空间利用率低,GC的频率就会变高;

复制算法

在这里插入图片描述

复制算法会开辟两块内存空间,当标记完成之后,将存活对象拷贝到另外一个空间中,并将当前空间数据清除。这种方式可以解决内存碎片化问题,而且效率高。但意味着我需要更多的内存空间,比如1G的空间,由于需要复制就得拆分成两块500M的空间,所以也是很耗费内容的;

复制算法和标记清除算法如何选择?

一般如果程序对象一般占用空间较小的话,可以采用标记清除算法,这样空间利用率会比复制算法高;如果对象是比较大的话,选择复制算法的空间利用率会比较高,算法没有好坏,只有适不适合;

标记整理算法

在这里插入图片描述

标记整理算法在进行标记之后,将存活对象移动到一块,剩下的全部清理掉。这样就有碎片化带来的问题,也不像复制算法那样浪费空间;

分代收集算法

由于在垃圾回收时,会STW暂停用户线程,导致程序没响应,如果停顿时间过长,会导致服务宕机;所以堆空间过大会导致垃圾回收时间过长,所以将堆进行分代管理,分为年轻代和老年代;

在这里插入图片描述

当new对象时,会尝试将数据存储到Eden区,如果Eden区满了之后会触发YGC,年轻代采用复制算法,第一次将存活对象复制到survivor0区,第二次会将survivor0和Eden区存活的对象复制到survivor1区,就这样反复在survivor0和survivor1间复制。

当年轻代的存活对象存活时间较长时,导致年轻代剩余空间变小,YGC就会变得很频繁;针对这种情况,给每个存活对象设置存活年龄,每次YGC后未被回收将年龄+1,当年龄到达阈值时(默认15),将其迁移到年轻代中;

当老年代空间满了之后会触发FULL GC,此时会对年轻代和老年代进行垃圾回收,老年代的回收算法不同的垃圾回收器采用的机制不同;

总结

垃圾回收算法有多种,每种针对的场景不一样,没法说其好坏,只有综合业务场景,设备信息等因素挑选出适合程序的算法,现市面上垃圾回收器有多种就是针对不同场景而定制的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

InstructGPT:Training language models to follow instructions with human feedback

Training language models to follow instructions with human feedback 通过人类反馈的微调&#xff0c;在广泛的任务中使语言模型与用户的意图保持一致 aligning language models with user intent on a wide range of tasks by fine-tuning with human feedback 实验动机 …

AssetStudio工程导入VS各种报错解决

AssetStudio下载地址&#xff1a;https://github.com/Perfare/AssetStudio 工程导入&#xff0c;生成解决方案&#xff0c;然后报了一堆错。让我们来一个一个的解决 这个错误&#xff0c;是缺少System.Runtime.InteropServices.RuntimeInformation.dll文件&#xff0c;下载并添…

20230612 set1打卡

哈希表理论基础 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和

【leetcode】189.轮转数组

方法1&#xff1a; 先把原数组拷贝一份&#xff0c;然后先将原数组的后k个拷贝&#xff0c;再将前numsSize-k个拷贝 void rotate(int* nums, int numsSize, int k) {//可能存在k>numsSize的情况&#xff0c;先处理kk k % numsSize;//拷贝数组int arr[numsSize];int i 0;in…

计算机网络 | socket IPC(本地套接字domain)

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

大模型研究方向0611

文章目录 1. 大模型自身角度认知角度2.大模型的成本角度3. 大模型的评测角度4.大模型的安全角度5. 大模型结构角度 附上刘知远老师的见解&#xff1a;https://hub.baai.ac.cn/view/27283 1. 大模型自身角度认知角度 即大模型的理解&#xff0c;现在&#xff0c;大众普遍认为L…

0202性能分析-索引-MySQL

1 索引语法 创建索引 CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name(index_column_name,...);Index_name&#xff1a;规范为idx_表名_字段名... 查看索引 SHOW INDEX FROM table_name;删除索引 DROP INDEX index_name ON table_name;按照下列要求&#xff0c;创建…

V5.0.X版本 EMQX安装、卸载 以及使用

V5.0.X版本 EMQX安装、卸载 以及使用 一、卸载二、下载安装2.1 下载2.2 安装2.2.1 rpm安装2.2.2 tar安装 2.3 测试启动 三、EMQX使用 回到目录    回到末尾 EMQX为大规模分布式物联网 MQTT 消息服务器。提供高效可靠连接海量物联网设备&#xff0c;实时处理分发消息与事件流数…

leangoo领歌敏捷工具中,如何快速查看项目内所有任务卡片

项目管理员能不能快捷的查看整个项目内的所有任务&#xff1f; 能不能快捷查看项目内某一个成员的所有任务&#xff1f; 能不能快捷的在项目内通过一些条件选择查看任务&#xff1f; 可以导出项目内某一个人的所有任务吗&#xff1f;方便做一些统计 等等... 这些现在Leang…

武职301班-day01

实现永和小票页面 效果图 问题分析 把一个大的开发任务&#xff0c;先进行任务分析&#xff0c;把完成这个任务需要的技术点和开发步骤写出来。 开发分析 特点&#xff1a; htmlcss实现 1&#xff09;小票有宽度限制 2&#xff09;字体大小不一样&#xff0c;大部分字体大小…

解决获取taro全局配置文件失败,找不到配置文件失败问题

问题&#xff1a;这会导致项目初始化不成功&#xff0c;即要用vuets生成项目的话&#xff0c;依旧是wxml&#xff0c;js的文件&#xff0c;而不是vue文件 解决一&#xff1a;首先找到配置文件目录 删除taro开头的三项文件&#xff0c;再去node_modules下删除tarojs 然后去终…

Python的基础语法知识

1、变量 变量是一个代号&#xff0c;它代表的是一个数据。 在Python中&#xff0c;定义一个变量的操作包含两个步骤&#xff1a; ①为变量起一个名字 ②为变量指定其所代表的数据 这两个步骤在同一行代码中完成。 1.1 变量的命名规则 变量名可以由任意数量的字母、数字、下划…

实验五 标准ACL的配置【网络安全】

实验五 标准ACL的配置【网络安全】 前言推荐实验五 标准ACL的配置问题方案步骤 最后 前言 2023-6-8 18:54:22 以下内容源自《【网络安全】》 仅供学习交流使用 推荐 配置标准ACL 实验五 标准ACL的配置 问题 络调通后&#xff0c;保证网络是通畅的。同时也很可能出现未经…

vscode Delete `␍⏎·····`

在公司电脑首次拉取代码的时候&#xff0c;好多代码报错&#xff0c;在网上查了博客&#xff0c;确定是换行导致&#xff0c;但是参考网上的解决办法&#xff0c;没有解决&#xff0c;不管是设置 auto 还是命令行执行什么什么的&#xff0c;都不管用 下面介绍我的办法 首先&a…

CloudFlare系列--使用第三方来自定义CDN的IP(笨牛简洁版)

原文网址&#xff1a;CloudFlare系列--使用第三方来自定义CDN的IP(笨牛简洁版)_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍CloudFlare的CDN如何自定义第三方IP。 概述 CloudFlare官网接入域名的方式只能是 NS 接入&#xff0c;这样默认DNS服务器只能改为CloudFlare的D…

Hibernate框架【五】——基本映射——多对多映射

系列文章目录 Hibernate框架【三】——基本映射——一对一映射 Hibernate框架【四】——基本映射——多对一和一对多映射 基本映射——多对多映射 系列文章目录前言一、多对多映射是什么&#xff1f;二、hibernate多对多关联映射&#xff08;单向&#xff09;1.实体结构2.示意…

大麦一键生成订单截图 大麦生成购票链接

一键生成订单截图&#xff0c;生成购票链接 已对接支付 下载程序&#xff1a;https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

【并发篇】04-05 线程池核心参数代码演示

B站 黑马程序员 java八股的视频笔记 自留备忘 如有错误请多多指教。 &#xff08;一&#xff09;理论知识 这道题其实就是在问java中线程池的实现类ThreadPoolExecutor&#xff0c;这个类参数最多的构造方法有7个参数。 线程池本质上就是管理一组线程&#xff0c;用来执行提交…

2023最新最全面Java复习路线(含P5-P8),已收录 GitHub

小编整理出一篇 Java 进阶架构师之路的核心知识&#xff0c;同时也是面试时面试官必问的知识点&#xff0c;篇章也是包括了很多知识点&#xff0c;其中包括了有基础知识、Java 集合、JVM、多线程并发、spring 原理、微服务、Netty 与 RPC 、Kafka、日记、设计模式、Java 算法、…

音视频技术开发周刊 | 297

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 Geenee AR为品牌商和零售商提供虚拟试穿应用 这意味着Geenee AR的虚拟试穿解决方案能够与品牌商现有的销售渠道无缝集成。 谁说苹果掉队了&#xff1f;WWDC上只字未提AI&a…