【JAVAEE】JVM中垃圾回收机制 GC

news2024/11/28 14:34:48

 

  • 博主简介:想进大厂的打工人
  • 博主主页:@xyk:
  • 所属专栏: JavaEE初阶 

上篇文章我们讲了java运行时内存的各个区域。

传送门:【JavaEE】JVM的组成及类加载过程_xyk:的博客-CSDN博客

对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言,其生命周期与相关线程有关,随线程而生,随线程而灭。并且这三个区域的内存分配与回收具有确定性,因为当方法结束或者线程结束时,内存就自然跟着线程回收了。因此我们本篇所讲的有关内存分配和回收关注的为Java堆与方法区这两个区域。


目录

文章目录

一、垃圾回收机制—GC

1.1 引用计数器算法(java没有采用这种算法)

1.2 可达性分析

二、垃圾回收算法

2.1 标记清除算法

2.2 复制算法

2.3 标记整理算法

2.4 复合策略”分带回收“

三、垃圾收集器

3.1 CMS收集器(老年代收集器,并发GC)

3.2 G1收集器(唯一一款全区域的垃圾回收器)


一、垃圾回收机制—GC

在JVM中存在一个垃圾回收机制,GC,帮助程序猿自动释放内存的,能够有效的减少内存泄漏的出现频率。主要是针对 堆上的对象 来进行释放~

GC也就是以 对象 为单位进行释放的(说是释放内存,其实是释放对象)

GC中主要分成两个阶段:

1.找,谁是垃圾

2.释放,用什么算法

Java堆中存放着几乎所有的对象实例,垃圾回收器在对堆进行垃圾回收前,首先要判断这些对象哪些还存活,哪些已经"死去"。判断对象是否已"死"有如下几种算法

死亡对象的判断算法:

1.1 引用计数器算法(java没有采用这种算法)

引用计算器判断对象是否存活的算法是这样的:给每一个对象设置一个引用计数器,每当有一个地方引用这个对象的时候,计数器就加1,与之相反,每当引用失效的时候就减1。当计数器为0,则认为没有对象了,就是垃圾了~

优点:实现简单、性能高。

缺点:增减处理频繁消耗cpu计算、计数器占用很多位浪费空间(每个对象都需要分配一个计数器)、最重要的缺点是无法解决循环引用的问题。

什么是循环引用?

存在两个对象,同时互相引用指向对象

 

此时,如果a和b都销毁了,这个时候,两个对象的引用计数给自减1,但是这两个对象的引用计数不是0,不能作为垃圾,无法回收,这俩个对象也无法使用了~陷入了一个逻辑上的循环

1.2 可达性分析

把对象之间的引用关系,理解成了一个树形结构,从一些特殊的起点出发,进行遍历,只要能遍历访问到的对象,就是”可达“,再把”不可达的“当作垃圾回收即可

通过 root 这个引用,就可以访问到整个树的任意结点,那么哪些对象可以作为gcroot?

  1. 栈上的局部变量(每个栈的每个局部变量,都是起点)
  2. 常量池中的引用的对象
  3. 方法区中,静态成员引用的对象

可达性分析,克服了引用计数的两个缺点~

但是也有自己的问题:

1.消耗更多的时间,因此某个对象成了垃圾,也不一定第一时间发现,每次扫描的过程,都是需要消耗时间的

2.在进行可达性分析的时候,要顺藤摸瓜,一旦这个过程中,代码的对象引用关系发生变化了,就麻烦了

因为,为了更准确的完成这个”摸瓜“的过程,需要让其他的业务线程 暂停工作!!(STW问题

stop the world,为了保证内存的一致性,必须先暂停程序的执行)

二、垃圾回收算法

上面我们可以通过可达性分析找到垃圾,那么我们应该用什么回收算法来进行回收操作呢?

2.1 标记清除算法

标记-清除算法是最基础的算法,像它的名字一样算法分为“标记”和“清除”两个阶段,首先需要标记出所需要回收的对象,标记完成后统一收集被标记的对象。

优点: 实现简单。

缺点: 产生不连续的内存碎片;“标记”和“清除”的执行效率都不高。如果要申请空间比较大,会失败。

2.2 复制算法

"复制"算法是为了解决"标记-清理"的效率问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另一块上面,然后再把已经使用过的内存区域一次清理掉。

 

优点: 执行效率高。

缺点: 空间利用率低, 因为复制算法每次只能使用一半的内存。

2.3 标记整理算法

类似于 顺序表删除中间元素,有一个搬运过程~
 

优点: 解决了内存碎片问题,比复制算法空间利用率高。

缺点: 因为有局部对象移动,相对效率不高。

2.4 复合策略”分带回收“

因此,实际上 JVM 的实现思路,是结合了上述几种思想方法,针对不同的情况,使用不同的策略.

给对象设定了”年龄“这样的概念,描述了这个对象存在多久了,如果一个对象刚诞生,认为是0岁,每次经过一轮扫描,没被标记成垃圾,这个时候对象就涨一岁,通过年龄来区分这个对象的 存活时间

1.新创建的对象,放到伊甸区,当垃圾回收扫描伊甸区之后,绝大部分对象都会在第一轮 GC 中就被干掉~~ 大部分对象是活不过一岁的,朝生夕死

2.如果伊甸区的对象,熬过第一轮 GC ,就会通过复制算法,拷贝到幸存区,幸存区分成两半大小,一次只使用其中的一半~~ 垃圾回收扫描幸存区的对象,也是发现垃圾就淘汰,不是垃圾的,通过复制算法,复制到幸存区的另外一半

3.当这个对象在幸存区,熬过若干轮 GC 之后,年龄增长到一定程度了,就会通过复制算法拷贝到老年代

4.进入老年代的对象,年龄都很大了,再消亡的概率比前面新生代中的对象小,针对老年代 GC 的扫描频次就会降低很多,如果老年代发现某个对象是垃圾了,使用标记整理的方式清除

5.特殊情况,如果对象非常大,直接进入老年代(大对象进行复制算法,成本比较高,而且大对象也不会很多)

三、垃圾收集器

3.1 CMS收集器(老年代收集器,并发GC)

特性:
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前
很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速
度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。
CMS收集器是基于“标记—清除”算法实现的,它的运作过程相对于前面几种收集器来说更复杂一些,整个过程分为4个步骤:

初始标记(CMS initial mark)
初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,需要“Stop The
World”。


并发标记(CMS concurrent mark)
并发标记阶段就是进行GC Roots Tracing的过程。


重新标记(CMS remark)
重新标记阶段是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分
对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的
时间短,仍然需要“Stop The World”。


并发清除(CMS concurrent sweep)
并发清除阶段会清除对象

由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的

缺点:

  1. CMS收集器对CPU资源非常敏感
  2. CMS收集器无法处理浮动垃圾 
  3. CMS收集器会产生大量空间碎片

 

3.2 G1收集器(唯一一款全区域的垃圾回收器)

G1(Garbage First)垃圾回收器是用在heap memory很大的情况下,把heap划分为很多很多的
region块,然后并行的对其进行垃圾回收

G1垃圾回收器回收region(区域)的时候基本不会STW,而是基于 most garbage优先回收(整体来看是基于"标记-整理"算法,从局部(两个region之间)基于"复制"算法) 的策略来对region进行垃圾回收的。

一个region有可能属于Eden,Survivor或者Tenured内存区域。图中的E表示该region属于Eden内存区域,S表示属于Survivor内存区域,T表示属于Tenured内存区域。图中空白的表示未使用的内存空间。G1垃圾收集器还增加了一种新的内存区域,叫做Humongous内存区域,如图中的H块。这种内存区域主要用于存储大对象-即大小超过一个region大小的50%的对象

1.年轻代垃圾收集
在G1垃圾收集器中,年轻代的垃圾回收过程使用复制算法。把Eden区和Survivor区的对象复制到新的Survivor区域

 2.老年代垃收集

1.初始标记(Initial Mark)阶段 - 同CMS垃圾收集器的Initial Mark阶段一样,G1也需要暂停应用程序的执行,它会标记从根对象出发,在根对象的第一层孩子节点中标记所有可达的对象。

2.并发标记(Concurrent Mark)阶段 - 在这个阶段G1做的事情跟CMS一样。但G1同时还多做了一件事情,就是如果在Concurrent Mark阶段中,发现哪些Tenured region中对象的存活率
很小或者基本没有对象存活,那么G1就会在这个阶段将其回收掉,而不用等到后面的clean
up阶段。
 

3.最终标记(CMS中的Remark阶段) - 在这个阶段G1做的事情跟CMS一样, 但是采用的算法不
同,G1采用一种叫做SATB(snapshot-at-the-begining)的算法能够在Remark阶段更快的标
记可达对象。

4.筛选回收(Clean up/Copy)阶段 - 在G1中,没有CMS中对应的Sweep阶段。相反 它有一个
Clean up/Copy阶段,在这个阶段中,G1会挑选出那些对象存活率低的region进行回收,这个
阶段也是和minor gc一同发生的,如下图所示

G1(Garbage-First)是一款面向服务端应用的垃圾收集器。HotSpot开发团队赋予它的使命是未来可以替换掉JDK 1.5中发布的CMS收集器。 如果你的应用追求低停顿,G1可以作为选择;如果你的应用追求吞吐量,G1并不带来特别明显的好处。

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

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

相关文章

6.S081——CPU调度部分(CPU的复用和调度)——xv6源码完全解析系列(10)

0.briefly speaking 终于到这里了,我们在之前阅读很多地方的内核代码时,总是习惯性地绕开CPU调度的部分(比如yield函数)。现在我们总算可以深入进去一探究竟了,这次总算是将整个操作系统中的一块重要拼图拼上去了。 有操作系统相关基础概念…

5 字符串拼接

5 字符串拼接作者: 赵晓鹏时间限制: 1S章节: 动态规划与贪心 输入说明 : 见问题描述。 输出说明 : 见问题描述。 输入范例 : aaaaaaaaaab aaaaaaaac aaaaaaaaaacaaaaaaaab 输出范例 : YES aa_________aaaaaaaab #include<iostream> #include<vector> using …

【数据分析 - 基础入门之pandas篇②】- pandas数据结构——Series

文章目录 前言一、Series的创建1.1 列表创建1.2 NumPy数组创建1.3 字典创建 二、Series索引2.1 显式索引2.2 隐式索引 三、Series切片2.1 显式切片2.2 隐式切片 四、Series基本属性和方法4.1 属性4.2 方法4.3 案例——使用 bool 值去除空值 五、Series运算六、Series多层行索引…

带你全面了解四大内存操作函数memset(),memcpy(),memmove(),memcmp()(附模拟实现)

内存操作函数 文章目录 内存操作函数memcpymemmovememcmpmemset 注&#xff1a;点击蓝色标题可以跳转到官方网站查看更权威的解析哦。 memcpy void * memcpy ( void * destination, const void * source, size_t num );函数memcpy从source的位置开始&#xff0c;向后复制num个…

Linux - CentOS 7 源码安装 MySQL 8.0.31

一、mysql-boost-8.0.31.tar.gz 源码下载 下载地址&#xff1a;https://dev.mysql.com 二、源码安装 MySQl 要求 cmake、Boost C库、ncurses库、OpenSSL库 //需要cmake3&#xff0c;gcc-5.3以上&#xff1b; 三、源码搭建 MySQL 环境 1、创建用户名和组 groupadd mysql …

ChatLaw团队招实习生啦!真格基金的创业、投资与AI详细指南;远程工作的8个安全法则;游戏开发者的数学教程 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 北大 ChatLaw 团队招聘实习生&#xff0c;开放算法和前后端岗位 ChatLaw 是一个开源的中文法律大模型&#xff0c;由北京大学与北大-兔…

vim编辑器中实现左边目录,右边内容布局的方法(vim插件:显示树形目录插件NERDTree安装和使用)

NERDTree&#xff1a;是Vim编辑器的文件系统资源管理器。使用此插件&#xff0c;用户可以直观地浏览复杂的目录层次结构&#xff0c;快速打开文件进行读取或编辑&#xff0c;并执行基本的文件系统操作。 它允许轻松浏览文件&#xff0c;并在不离开vim的情况下执行一些基本操作…

Spring Cloud的基本应用

上篇文章我们的eureka的集群已经搭建完毕,但是我们还没有开始使用,之前我们的page访问的方法是直接写死的,现在我们就可以改为集群的方式来写 Autowired//注册中心对应的客户端对象private DiscoveryClient discoveryClient;RequestMapping("query/{id}")public Prod…

基于51单片机的智能垃圾桶

功能&#xff1a; 本实例是基于51单片机为核心的智能垃圾桶仿真&#xff0c;主要由51单片机最小系统、L298N电机驱动电路、开盖电机、超声波传感器、红外测速模块、直流电机、红外人体传感器、LCD1602显示屏、震动传感器、按键电路构成。 1.系统的传感器主要用人体感应和机体震…

订单结算页+下单业务

一、订单结算页 1.业务分析 (1) 获取用户收货地址信息 一般的收货地址都是多个&#xff0c;使用时选中一个&#xff0c;所以收货地址使用List集合封装 (2)获取购物车商品信息 购物车商品也是多个&#xff0c;使用List集合封装 (3)查询商品库存 查询每个商品是否有库存&#…

VSCode安装及环境配置详细教程(windows版本)

目录 安装VSCode 安装Python 检查环境变量 检查Python是否能运行 VSCode环境配置 切换成简体中文 添加Python插件 编写代码运行 &#xff01;&#xff01;请先在官网下载Python和VSCode安装包&#xff0c;保存至本地 Python官网&#xff1a;https://www.python.org/do…

多元回归预测 | Matlab基于灰狼算法(GWO)优化高斯过程回归(GWO-GPR)的数据回归预测,matlab代码,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于灰狼算法(GWO)优化高斯过程回归(GWO-GPR)的数据回归预测,matlab代码,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源…

APP测试要点有哪些?

我们日常购物、旅游、支付等活动都离不开手机&#xff0c;由此衍生了很多APP。 比如每天使用频率非常高的微信、支付宝、微博、抖音、王者荣耀等等。 APP测试主要进行功能测试、性能测试、自动化测试、安全性测试、兼容性测试、专项测试。 01、APP测试流程 APP测试流程与web测…

软考A计划-系统集成项目管理工程师-项目进度管理-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

python glob库glob函数返回为空时

这里的max函数会报空序列的错误&#xff0c;原因就是glob.glob函数读取不到文件的问题&#xff0c;推测是脚本所在文件夹与传入的文件夹地址不对造成的&#xff0c;比如C&#xff1a;/tor/data/jiaoben.py,而文件所在文件夹是C&#xff1a;/tor/biaobei/

自媒体13条监管新规来了:做自媒体还有前途吗?

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 各位自媒体人&#xff0c;大家一定要逐条逐句&#xff0c;认真研读&#xff0c;领会精神&#xff0c;掌握要求&#xff0c;规范运营好自己的账号&#xff0c;切莫越界踩线&#xff0c;多为广大网友…

邮箱推荐和(警告)使用qq邮箱的坏处

qq如果发布违规消息&#xff0c;比如群聊无意发布会导致你账号封号&#xff0c;而且随着次数增多&#xff0c;会导致永久封号&#xff0c;你的qq音乐&#xff0c;qq浏览器&#xff0c;qq游戏&#xff0c;{qq邮箱}&#xff0c;全部会无法登录&#xff0c;比如需要登陆邮箱验证码…

初学者也能轻松掌握的MQL4编程入门指南

MQL4编程是外汇交易中极为重要的一部分&#xff0c;掌握MQL4编程可以帮助交易者快速创建自己的交易算法&#xff0c;进而提高交易效率和盈利水平。但是对于初学者来说&#xff0c;MQL4编程可能会显得有些困难。本篇文章就是为初学者准备的&#xff0c;针对MQL4编程进行入门指导…

对RAM和ROM的理解

什么是RAM、ROM&#xff1f; RAM(Random Access Memory)随机存取存储器 ROM(Read Only Memory)只读存储器 先记住一件事 RAM断电将失去数据 ROM断电仍会保留数据 RAM、ROM、Flash、内存条、硬盘、SD卡到底怎么归类&#xff1f; 我们先来看下计算机的原理和计算机的需求 …

【Leetcode】59. 螺旋矩阵II

给定一个正整数 n&#xff0c;生成一个包含 1 到 n^2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的正方形矩阵。 示例: 输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ] 面试频率较高 1. 先定义一个空矩阵 2. startx表示行起始 starty表示列起始 3. 左闭右开…