【JVM详解三】垃圾回收机制

一、对象是否存活

  • 强引用:Object obj = new Object(); 只要强引用还在,垃圾收集器永远不会回收掉被引用的对象。在不用对象的时将引用赋值为 null,能够帮助垃圾回收器回收对象。比如 ArrayList 的 clear() 方法实现。
  • 软引用(SoftReference):用来描述一些非必须但还有用的对象。在系统将要发生内存溢出异常时回收,若还没有足够的内存才会OOM。
  • 弱引用(WeakReference):也是用来描述非必须对象,强度比软引用更弱;被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器开始工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
  • 虚引用:也被称为幽灵引用或幻影引用。该引用最弱,一个对象是否有虚引用的存在完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象。为一个对象设置虚引用关联的唯一目的就是能在这个对象被垃圾收集器回收时收到一个系统通知。

1.1 引用计数算法

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就+1;当引用失效时,计数器值就-1;任何时刻计数器为0的对象就是不可能再被使用的。

优点:实现简单,判定效率高。

缺点:假设对象objA和objB都有字段instance,赋值令objA.instance = objB 及 objB.instance = objA,除此之外这两个对象再无任何引用,实际上这两个对象不可能再被访问,但是因为它们互相引用着对方,导致它们的引用计数器都不为0,于是引用计数器无法通知GC收集器回收它们。

1.2 可达性分析算法

基本思路是 通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,它们将会被判定为可回收对象。

GC Roots:一组必须活跃的对象
可作为GC Roots的对象包括以下几种:
  • java虚拟机栈(栈帧中的局部变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(即一般说的Native方法)引用的对象

finalize()赋予对象重生 :

在可达性分析算法中被标记为不可达的对象,也不一定是一定会被回收,它还有第二次重生的机会。每一个对象在被回收之前要进行两次标记,一次是没有关联引用链会被标记一次,第二次是判断该对象是否覆盖finalize()方法,如果没有覆盖则真正的被定了“死刑”。

如果这个对象被jvm判定为有必要执行finalize()方法,那么这个对象会被放入F-Queue队列中,并在稍后由一个由虚拟机自动创建的、低优先级的finalizer线程去执行它。但是这里的“执行”是指虚拟机会触发这个方法,但是**并不代表会等它运行结束。虚拟机在此处是做了优化的,因为如果某个对象在finalize方法中长时间运行或者发送死循环,将可能导致F-Queue队列中其他对象永远处于等待,甚至可能会导致整个内存回收系统崩溃。

如果要在finalize方法中重生这个对象你可以按照下面代码做:

 注意!finalize()方法只会被系统调用一次,多次被gc只有第一次会被调用,因此只有一次的重生机会。

二、垃圾回收算法

2.1 标记-清除算法

算法分 “标记”和“清除”两个阶段:首先标记出所有需要所有需要回收的对象(可达性分析算法),在标记完成后统一回收所有被标记的对象。之所以说是最基础的算法,是因为后续的收集算法基于这种思路并对其不足进行改进而得到的。
不足之处:
  • 效率问题,标记和清除两个过程效率都不高
  • 空间问题,标记清除后会产生大量不连续的内存碎片,可能会导致后续程序运行过程需要分配较大对象时,无法找到足够的连续内存而不得不提前触发一次垃圾回收操作。

2.2 复制算法(年轻代GC)

缺点:对象存活率较高时就要进行更多的复制操作,效率将会变低。

最开始是将可用内存分为大小相等的两块,每次只使用其中一块,当这一块内存用完了,就将还存活的对象复制到另一块上,然后再把已使用的那块内存空间清理掉。

因这种算法代价太大,将可用内存缩小到了原来的一半,所以后续IBM公司研究发现年轻代98%的对象都是“朝生夕死”的,并不需要按1:1划分,所以对算法进行了优化。

上图是优化后的划分。这种划分每次年轻代可用内存达到90%。当我们没有办法保证每次回收都只有不多于10%的对象存活时,需要依赖老年代进行分配担保。

空间分配担保:

     在发生Minor GC(Yong GC)之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象总空间。

           如果大于,则此次Minor GC(Yong GC)是安全的。

           如果小于,jdk1.6之前:则虚拟机会查看 HandlePromotionFailure 设置值是否允许担保失败。如果 HandlePromotionFailure=true ,那么会继续检查老年代最大可用连续空间是否大于历次晋升到老年代的对象的平均大小。如果大于,则尝试进行一次 Minor GC(Yong GC),但这次Minor GC(Yong GC)依然是有风险的,失败后会重新发起一次 Full GC;如果小于或者HandlePromotionFailure=false,则改为直接进行一次 Full GC。

但是在jdk1.6 update 24之后 -XX:-HandlePromotionFailure 不起作用了,只要老年代的连续空间大于新生代对象的总大小或者历次晋升到老年代的对象的平均大小就进行MinorGC,否则FullGC。

2.3 标记-整理算法

首先标记出所有需要所有需要回收的对象(可达性分析算法),然后让所有存活对象都向一端移动,然后直接清理端边界以外的内存。

2.4 分代收集算法

根据对象的存活周期将不同的内存划分成几块,一般是把 java 堆划分成年轻代和年老代,这样可以根据各个年代的特点分别采用最适当的收集算法。新生代一般选用复制算法,年老代一般选用“标记---清除”或者“标记---整理”算法。

 核心参数:

  • -XX:NewSize :指定新生代初始大小。
  • -XX:MaxNewSize :指定新生代最大大小。
  • -XX:NewRatio :是年老代 新生代相对的比例,比如NewRatio=2,表明年老代是新生代的2倍。老年代占了heap的2/3,新生代占了1/3。
  • -XX:SurvivorRatio :配置的是在新生代里面Eden和一个Survivor比例。
-XX:SurvivorRatio=8表示新生代的Eden占8/10,S1和S2各占1/10.
  • -XX:MaxTenuringThreshold用来定义年龄的阈值,达到阈值进入年老代。默认15。
  • -XX:PretenureSizeThreshold 的意思是大小超过这个值的时候,对象直接在old区分配内存。
  • -XX:HandlePromotionFailure 设置值是否允许担保失败。jdk1.6后失效。
GC过程:
new 的对象直接进入 Eden 区(对象太大直接进入年老代),Eden 区没有足够空间分配时,发起一次 minor gc :Eden 区和From Survivor空间还幸存的对象拷贝到To Survivor空间,然后清空Eden区和From Survivor空间,然后把To Survivor空间和From Survivor空间名字对换,幸存对象age+1。
当执行 minor gc 时To Survivor空间满了,则Eden区中的对象将进入老年代;当对象age=15时也将进入老年代;当Survivor空间age相同的对象(假设为ageA)总和 >= survivor空间的一半时,Survivor空间中age > ageA 的对象也将进入年老代。虚拟机进行minor gc时,当要进入年老代的对象 > 年老代剩余空间大小,将发生 Full GC(整个堆GC,包括年轻代和年老代)。

三、垃圾收集器

3.1 Serial收集器

新生代收集器,采用复制算法;单线程;GC时需要暂停用户线程。最高的单线程收集效率,对于运行在 Client 模式下的虚拟机来说是一个很好的选择。

Serial Old收集器:是Serial收集器的老年代版本;单线程;使用“标记---整理”算法。

3.2 ParNew收集器

新生代收集器,采用复制算法,Serial收集器的多线程版本;GC时需要暂停用户线程。

3.3 Parallel Scavenge收集器

 新生代收集器,采用复制算法;多线程;GC时需要暂停用户线程。和ParNew区别在于Parallel ScaVenge收集器目标是达到一个可控制的吞吐量吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)

  • -XX:MaxGCPauseMillis 控制最大垃圾收集停顿时间。大于0的毫秒数,改值缩短需要牺牲吞吐量和新生代空间。
  • -XX:GCTimeRadio 直接设置吞吐量大小。0到100之间的整数,垃圾收集时间占总时间的比例。
  • -XX:+UseAdaptiveSizePolicy 一个开关参数,打开后不需手动指定新生代大小(-Xmn)、Eden区域Survivor空间的比例(-XX:SurvivorRadio)、晋升老年代对象大小(-XX:PretenureSizeThreshold) 等细节参数,虚拟机会根据当前系统运行情况收集性能监控信息,动态调整以提供最合适的停顿时间或者最大的吞吐量,这种条件被称为GC的自适应调节策略(GC Ergonomics)。
Parallel Old收集器:是Parallel Scavenge收集器的老年代版本;多线程;使用“标记---整理”算法;jdk1.6开始提供。

3.4 CMS收集器(重点)

标记-清除算法;以获取低停顿为目标。适合互联网网站或者 B/S(Brower/Server 浏览器/服务器模式)系统的服务端。运作过程分为4个步骤:

  • 初始标记:非并行,需要停止用户线程,标记GC Roots能关联到的对象。很快。
  • 并发标记:并行,不停止用户线程,进行GC Roots Tracing(追踪)的过程。慢。
  • 重新标记:并行,需要停止用户线程,修正并发标记期间因用户程序继续运作而导致标记产生变动的那些对象的标记记录。快
  • 并发清除:并行,不停止用户线程

优点:并发收集,低停顿。

缺点:

  • 对CPU资源非常敏感:并发设计的程序对CPU资源都敏感;在并发阶段会因为占用了一部分CPU资源而导致用户应用程序变慢,总吞吐量会降低。
  • 无法处理浮动垃圾:由于CMS并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾产生,这一部分垃圾出现在标记过程之后,所以CMS在本次并发清理过程无法处理掉它们,只好留待下一次GC时再清理。这部分垃圾称为浮动垃圾。由于在垃圾收集阶段用户线程还在运行,所以需要预留足够的内存空间给用户线程使用,因此CMS不能等老年代几乎被填满时再进行收集,需要预留部分空间提供给并发收集时用户线程运行使用。jdk1.5默认老年代使用了68%激活Full GC,jdk1.6改为92%,可通过-XX:CMSInitiatingOccupancyFraction设置。
  • 基于“标记---清除”算法,产生大量空间碎片

3.5 G1收集器(重点)

面向服务端应用,追求低停顿(还能建立可预测的停顿时间模型),基于“标记---整理”算法。

在G1之前的其他收集器进行GC的范围都是整个新生代或者老年代,而G1对java堆的内存布局和其他收集器有很大差别。它将整个java堆分为多个大小相等的独立区域(Region),虽然还保留新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,他们都是一部分Region的集合。

G1可以有计划的避免在整个java堆中进行Full GC:G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(Garbage-First的由来)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限时间内可以获取尽可能高的收集效率。

G1中每个Region都有一个与之对应的Rememberd Set,用于避免全堆扫描:虚拟机在发现程序对Reference类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作,检查Reference引用的对象是否处于不同的Region中(在分代的例子就是检查是否是老年代中的对象引用了年轻代的对象),如果是 则通过CardTable把相关引用信息记录到被引用对象所属的Region的Rememberd Set中。当进行内存回收时,在GC Roots的枚举范围内加入Rememberd Set即可保证不对全堆扫描也不会有遗漏。

区域 (Region) 的大小,可以通过 -XX:G1HeapRegionSize 参数指定,大小区间最小 1M 、最大 32M ,总之是 2 的幂次方。默认是将堆内存按照 2048 份均分。

运作过程如下:

  • 初始标记 :非并行,需要停止用户线程,标记GC Roots能直接关联到的对象。
  • 并发标记 :并行,从GC Roots开始对堆中对象进行可达性分析,找出存活对象。
  • 最终标记 :并行,需要停止用户线程,修正并发标记期间因用户程序继续运作而导致标记产生变动的那些对象的标记记录,并将这些变化记录在Rememberd Set Logs中,最后将Rememberd Set Logs数据合并到Rememberd Set中。Rememberd Set : 记录对象在不同分区的引用关系
  • 筛选回收 :并行,需要停止用户线程,首先对各个Region的回收价值和成本进行排序,然后根据用户期望的GC停顿时间来制定回收计划。G1 中提供了 Young GCMixed GC 两种垃圾回收模式,这两种垃圾回收模式,都是 Stop The World (STW) 的。
优点如下:
  • 并行与并发
  • 分代收集
  • 空间整合
  • 可预测的停顿
在以下场景中,G1 更适合:
  • 服务端多核 CPU、JVM 内存占用较大的应用(至少大于 4G);
  • 应用在运行过程中,会产生大量内存碎片、需要经常压缩空间;
  • 想要更可控、可预期的 GC 停顿周期,防止高并发下应用雪崩现象。

3.6 JVM垃圾收集相关参数

3.7 各个版本jdk默认的垃圾收集器

各个版本JDK默认的垃圾回收器:
  • JDK1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
  • JDK1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
  • JDK1.9 默认垃圾收集器G1
//查看当前使用的垃圾收集器
java -XX:+PrintCommandLineFlags -version
-XX:+UseSerialGC :设置串行收集器
-XX:+UseParallelGC :设置并行收集器
-XX:+UseParalledlOldGC :设置并行年老代收集器
-XX:+UseConcMarkSweepGC :设置并发收集器

四、内存分配与回收策略

  • 对象优先在Eden分配
  • 大对象直接进入老年代(-XX:PretenureSizeThreshold 配置对象大小阈值)
  • 长期存活的对象进入老年代(-XX:MaxTenuringThreshold 配置年龄大小阈值,默认15岁)
  • 动态对象年龄判定:在Survivor空间中相同年龄所有对象大小的总和 > Survivor空间的一半时,年龄 > 该年龄的对象就可以直接进入老年代。
  • 空间分配担保:在发生minor gc之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么minor gc可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置的值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次minor gc,尽管此次minor gc有风险;如果小于,或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC。

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

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

相关文章

【免费】2007-2020年各省医疗卫生支出数据

2007-2020年各省医疗卫生支出数据 1、时间:2007-2020年 2、来源:国家统计局、统计年鉴 3、指标:行政区划代码、地区名称、年份、医疗卫生支出 4、范围:31省 5、指标说明:地方财政医疗卫生支出是指地方ZF从其财政预…

【深度学习入门实战】基于Keras的手写数字识别实战(附完整可视化分析)

​ 本人主页:机器学习司猫白 ok,话不多说,我们进入正题吧 项目概述 本案例使用经典的MNIST手写数字数据集,通过Keras构建全连接神经网络,实现0-9数字的分类识别。文章将包含: 关键概念图解完整实现代码训练过程可视化模型效果深度分析环境准备 import numpy as np impo…

腾讯云大数据套件TBDS与阿里云大数据能力产品对比

前言 博主在接触大数据方向研究的时候是在2016年,那时候正是大数据概念非常火热的一个时间段,最著名的Google的3篇论文。Google FS、MapReduce、BigTable,奠定了大数据框架产品的基础。Google文件系统,计算框架和存储框架。往后所有的大数据产品和过程域无一不是在三个模块…

前端如何判断浏览器 AdBlock/AdBlock Plus(最新版)广告屏蔽插件已开启拦截

2个月前AdBlock/AdBlock Plus疑似升级了一次 因为自己主要负责面对海外的用户项目,发现以前的检测AdBlock/AdBlock Plus开启状态方法已失效了,于是专门研究了一下。并尝试了很多方法。 已失效的老方法 // 定义一个检测 AdBlock 的函数 function chec…

2.11寒假作业

web:[SWPUCTF 2022 新生赛]js_sign 打开环境是这样的,随便输入进行看看 提示错误,看源码其中的js代码 这个代码很容易理解,要让输入的内容等于对应的字符串,显然直接复制粘贴是错的 这串字符看起来像是base64加密&…

c# http

C#代码 客户端: NETCore提供了三种不同类型用于生产的REST API: HttpWebRequest;WebClient;HttpClient HttpWebRequest 这是.NET创建者最初开发用于使用HTTP请求的标准类。使用HttpWebRequest可以让开发者控制请求/响应流程的各个方面,如…

哈希表实现(C++实现)

目录 1.哈希概念 2.哈希冲突 3.哈希函数 4.哈希冲突解决 闭散列 —— 开放定址法 线性探测 二次探测 开散列 —— 链地址法(拉链法、哈希桶) 5.哈希表的闭散列实现 哈希表的结构 哈希表的大小和扩容 哈希表的插入 哈希表的查找 哈希表的删除…

开箱即用:一个易用的开源表单工具!

随着互联网的普及,表单应用场景越来越广泛,从网站注册、调查问卷到考试测评,无处不在。传统的表单制作方式需要一定的代码基础,对于不懂编程的小伙伴来说,无疑是一道门槛。 今天,给大家分享一款开源的表单…

牛客 BM1: 反转链表

目录 一、题目 二、C解题程序框架 1. 结构体定义 2. 类定义 3. 输入输出说明 三、链表指针 1. 链表指针的基本概念 2. 链表指针的常见操作 1. 遍历链表 2. 插入节点 3. 删除节点 3. 链表指针操作的注意事项 4. 总结 四、解题 方法一:迭代法 方法二&…

MIT开源7B推理模型Satori:用行动思维链进行强化学习,增强自回归搜索

自OpenAI的o1发布以来,研究社区为提升开源LLM的高级推理能力做出了诸多努力,包括使用强大的教师模型进行蒸馏、蒙特卡洛树搜索(MCTS)以及基于奖励模型的引导搜索等方法。 本研究旨在探索一个新的研究方向:使LLM具备自回…

Kubernetes控制平面组件:etcd(一)

云原生学习路线导航页(持续更新中) kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计(一)Kubernetes架构原则和对象设计(二)Kubernetes架构原则和对象设计(三)kubectl 和 …

Django在终端创建项目(pycharm Windows)

1.选择目录 选择或新建一个文件夹,作为项目保存的地方 2.右键在终端打开 3.确定django-admin.exe安装位置 找到自己安装django时,django-admin.exe安装的位置,例如 4.运行命令 使用django-admin.exe的绝对路径,在刚才打开的终端…

e2studio开发RA2E1(9)----定时器GPT配置输入捕获

e2studio开发RA2E1.9--定时器GPT配置输入捕获 概述视频教学样品申请硬件准备参考程序源码下载新建工程工程模板保存工程路径芯片配置工程模板选择时钟设置UART配置UART属性配置设置e2studio堆栈e2studio的重定向printf设置R_SCI_UART_Open()函数原型回调函数user_uart_callback…

【PS 2022】Adobe Genuine Service Alert 弹出

电脑总是弹出Adobe Genuine Service Alert弹窗 1. 不关掉弹窗并打开任务管理器,找到Adobe Genuine Service Alert,并右键进入文件所在位置 2 在任务管理器中结束进程并将文件夹中的 .exe 文件都使用空文档替换掉 3. 打开PS不弹出弹窗,解决&a…

RoboGrasp:一种用于稳健机器人控制的通用抓取策略

25年1月来自北京大学和哈佛大学的论文“RoboGrasp: A Universal Grasping Policy for Robust Robotic Control”。 模仿学习和世界模型在推进通用机器人学习方面显示出巨大的潜力,而机器人抓取仍然是实现精确操控的关键挑战。现有方法通常严重依赖机械臂状态数据和…

接口测试Day12-持续集成、git简介和安装、Gitee远程仓库、jenkins集成

持续集成 概念: 团队成员将自己的工作成果,持续集成到一个公共平台的过程。成员可以每天集成一次,也可以一天集成多 次。 相关工具: 本地代码管理:git远程代码管理:gitee(国内)、github(国外)、gitlib(公司…

C语言基础11:分支结构以及if的使用

C语言基础 内容提要 分支结构 条件判断用if语句实现分支结构 分支结构 问题抛出 我们在程序设计往往会遇到如下问题,比如下面的函数的计算: y { 1 / x 当 x ≠ 0 时 10000 当 x 0 时 y \begin{cases} 1/x \quad当x\neq0时\\ \\ 10000 \quad当x0…

81页精品PPT | 华为流程与信息化实践与架构规划分享

华为流程与信息化实践与架构规划分享主要围绕华为在业务流程与信息化建设方面的经验、企业架构规划方法以及企业数字化转型路径展开。华为通过持续的业务变革和信息化建设,从本土企业逐步发展为国际化、全球化企业,其管理体系以持续创新和世界级管理体系…

【最大开支——优先队列,计算增量】

题目 代码 #include <bits/stdc.h> using namespace std; using ll long long; using pll pair<ll, int>; #define x first #define y second const int N 1e5 10; int n, m; int k[N], b[N], cnt[N]; priority_queue<pll, vector<pll>> pq; // d…

174款复古Y2K酸性镀铬银色金属多样化锁链链条铁链几何抽象PNG免扣元素设计套装 Studio 2AM - Chains

Chains 是以链条纹理为主题的设计元素的集合。以 PNG 格式以高分辨率创建&#xff0c;但文件大小较小&#xff0c;因此不会占用硬盘空间。“Chains” 是以 PNG 格式提供的以链条为主题的设计元素的高分辨率集合。该套装包括 174 个银色、生锈和彩虹色材料的链条纹理&#xff0c…