JVM常见的垃圾回收器

1、回收方法区:

        方法区回收价值很低,主要回收废弃的常量和无用的类。

方法区中的存储:
    方法区中存储的是加载的类的信息,常量,静态变量,即时编译后的代码等数据,所以回收的对象也就是这些内容。

何种场景需要回收:
    既然回收方法区不是必须的,虽然效率低下,但是当内存不够使用的时候依然是会抛出OOM的,那么我们需要知道什么场景下需要去回收方法区。首先我们需要弄明白方法区会回收那些对象。在JDK1.7之前,常量池是在方法区中的,在此版本及以后则将其移到堆中。基于目前版本主要是1.8及以上,故我们以1.8为准。在此版本上,主要回收的是无用的类。如何判定一个类是无用的:
 

  • 无用的类回收有以下条件:

        ①JAVA实例已经全部被回收,在堆中没有该类的示例存在;

        ②该类的classLoader被回收;

        ③该类的java.long.class对象没有被引用,不会被其他方法通过反射访问该类的方法

        与堆中的对象回收机制不同,不是不用即回收。HotSpot虚拟机提供了-Xnoclassgc参数进行控制是否回收。
 

2、垃圾回收器:

Serial、Serial Old、PawNew、CMS、Parallel Scavenge、Parallel Old、G1

  • Serial收集器,串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。
  • ParNew收集器,ParNew收集器其实就是Serial收集器的多线程版本。
  • Parallel收集器,Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量。
  • Parallel Old 收集器,Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
  • CMS收集器,CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
  • G1收集器,G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征

CMS垃圾收集器
 

CMS(并发标记清除收集器)(Concurrent Mark Sweep) 

        CMS是基于“标记-清除"算法实现的、以最短停顿时间为目标的垃圾收集器,CMS垃圾回收器主要针对老年代进行垃圾回收

        CMS回收垃圾的整个过程分为以下四个阶段:

                即初始标记阶段、并发标记阶段、重新标记阶段 和 并发清除阶段。

                (涉及STW,暂停用户线程的阶段主要是:初始标记 和 重新标记)

        CMS垃圾收集器在并发标记阶段并发清除阶段能让用户线程和GC线程并发执行,因此在整个垃圾收集过程中用户不会感到明显的卡顿:

  •         初始标记(Initial-Mark)阶段: 初始标记阶段会暂停所有的用户线程, 单线程标记与GC Roots直接关联的对象, 单线程标记是为了确保标记过程的准确性和一致性。这个阶段的主要任务仅仅只是标记出与GCRoots能直接关联到的对象。一旦标记完成之后就会立即进入并发标记阶段,恢复之前被暂停的所有用户线程。此外,由于与GC Roots直接关联对象比较少,所以初始标记阶段的速度非常快。
  •         并发标记(Concurrent-Mark)阶段:在并发标记阶段中,程序的工作线程会和垃圾回收线程并发执行或者交叉执行,垃圾回收线程会进行可达性分析,会从GC Roots直接关联的对象开始向下遍历堆中的对象图,标记所有可达的对象 。这个过程耗时较长但是不需要停顿用户线程。
  •         重新标记(Remark)阶段:由于工作线程在并发标记阶段可能会造成对象的引用发生变化,即原本可达的对象变成了垃圾对象,不可达对象变成了可达对象,所以重新标记阶段垃圾回收器会暂停所有工作线程,对在并发标记阶段中发生变化的对象进行重新标记、修正
    • 注意只能修正原有对象不能修正新增对象,即只能修正原有对象非可达变可达、可达变非可达。
  •         并发清除(Concurrent-Sweep)阶段:清理在标记阶段判断已经死亡的对象,释放内存空间。由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的

CMS缺点:

  1. 内存碎片问题:CMS 使用的是标记-清除算法,它会在回收垃圾对象之后产生大量的内存碎片。当老年代空间碎片太多时,如果无法找到一块足够大的连续内存存放对象时,将不得不提前触发一次Full GC。 

  2. 无法处理浮动垃圾:并发标记阶段用户线程可能会产生新对象,重新标记阶段只能修正原有对象非可达变可达、可达变非可达,不能新增,那么这些新增对象有可能在并发标记和并发清理阶段变为浮动垃圾对象,CMS 无法直接处理这些浮动垃圾,需要等到下一次 GC 才能回收。

  3. 并发标记引起的CPU资源紧张:在并发标记阶段,用户线程与垃圾回收线程并发执行,这可能会增加一定程度的 CPU 消耗

  4. 回收时要确保用户线程有足够内存:不能等老年代满了再回收,而是老年代内存到达某个阈值后回收,防止用户线程在并发执行过程中新创建对象导致内存不够,导致虚拟机补偿使用Serial Old收集器进行回收并处理内存碎片,从而浪费更多时间。默认情况下,当老年代使用了92%的空间后就会触发CMS垃圾回收机制。可以通过-XX:CMSInitiatingOccupancyFraction来设置 

  • 优点:
    • 并发速度快;
    • 低停顿:仅初始标记和重新标记阶段需要停顿用户线程,这两个阶段运行速度很快,CMS垃圾收集器在并发标记阶段并发清除阶段能让用户线程和GC线程并发执行,因此在整个垃圾收集过程中用户不会感到明显的卡顿。

演示非可达变为可达:

        在 main 方法中,首先创建了一个对象 obj,并将其设置为 null,使其成为不可达状态。然后,在后续代码中,通过 new 关键字重新创建了一个 MyClass 对象,并将其赋值给 obj,使得 obj 变为了可达状态。在这个过程中,就实现了非可达变可达的情况。

public class NonReachableToReachableExample {static class MyClass {// 类中的成员变量int data;// 类的构造函数MyClass(int data) {this.data = data;}}public static void main(String[] args) {// 创建一个 MyClass 对象并赋值给变量 obj,初始时它是不可达的MyClass obj = null;// 在并发标记阶段后,某个用户线程重新获取了对 obj 的引用,使得 obj 变为可达obj = new MyClass(10);// 在重新标记阶段,obj 被标记为可达// 在此之前,obj 是不可达的,但由于用户线程的活动,它变为了可达// 因此,在重新标记阶段需要修正这个状态}
}

G1垃圾回收器:

        G1(Garbage-First,垃圾优先收集器):

  •         G1垃圾回收器不再把堆划分为连续的分代,而是将堆内存分割成2048个大小相等的Region,各Region根据需要扮演伊甸园区、幸存区、老年代区、巨大区Humongous Region。垃圾优先收集器跟踪各Region里垃圾的回收价值(回收空间大小和预计回收时长),在后台维护一个优先级列表,每次根据用户设定允许的收集停顿时间,回收优先级最高的那些Region,以达到垃圾优先的效果。
  • 设置最大停顿时间:-XX:MaxGCPauseMillis=默认0.2s
  •          G1从整体来看是基于标记-整理算法实现的回收器,但从局部(两个Region之间)上看又是基于复制算法实现的。
  •         G1在JDK9之后成为了默认的垃圾回收器,取代了Parallel Scavenge 、Parallel Old默认组合,而CMS被声明为不推荐使用的垃圾回收器。  

步骤:

  •         初始标记:初始标记阶段会暂停所有的用户线程, 单线程标记与GC Roots直接关联的对象, 单线程标记是为了确保标记过程的准确性和一致性。这个阶段的主要任务仅仅只是标记出与GCRoots能直接关联到的对象。
  •         并发标记:在并发标记阶段中,程序的工作线程会和垃圾回收线程并发执行或者交叉执行,垃圾回收线程会进行可达性分析,从GC Roots直接关联的对象开始向下遍历堆中的对象图,标记所有可达的对象 。这个过程耗时较长但是不需要停顿用户线程。
  •         最终标记:重新标记所有存活的对象和上个阶段用户线程新产生的可达对象。并发停顿。采用SATB算法,效率比CMS重新标记高。并发停顿。
  •         筛选回收:根据优先级列表,回收价值高的一些Region,将存活对象通过标记复制算法复制到同类型的空闲Region。根据指定的最大停顿时间回收,因此可能来不及回收所有垃圾对象,但能保证回收到最高回收价值的垃圾。并发停顿。

初始标记阶段会暂停所有的用户线程, 单线程标记与GC Roots直接关联的对象, 单线程标记是为了确保标记过程的准确性和一致性。这个阶段的主要任务仅仅只是标记出与GCRoots能直接关联到的对象。一旦标记完成之后就会立即进入并发标记阶段,恢复之前被暂停的所有用户线程。此外,由于与GC Roots直接关联对象比较少,所以初始标记阶段的速度非常快。

Minor GC与Full GC分别在什么时候发生?

        新生代内存不够用时候发生MGC也叫YGC,JVM内存不够的时候发生FGC

引用的分类:

        强引用:GC时不会被回收

        软引用:描述有用但不是必须的对象,在发生内存溢出异常之前被回收

        弱引用:描述有用但不是必须的对象,在下一次GC时被回收

        虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用PhantomReference实现虚引用,虚引用用来在GC时返回一个通知。
 

 你知道哪些JVM性能调优:

设定堆内存大小

-Xmx:堆内存最大限制。

设定新生代大小。 新生代不宜太小,否则会有大量对象涌入老年代

-XX:NewSize:新生代大小

-XX:NewRatio 新生代和老生代占比

-XX:SurvivorRatio:伊甸园空间和幸存者空间的占比

设定垃圾回收器 年轻代用 -XX:+UseParNewGC 年老代用-XX:+UseConcMarkSweepGC

JVM的永久代中会发生垃圾回收么?

        垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。这就是为什么正确的永久代大小对避免Full GC是非常重要的原因。请参考下Java8:从永久代到元数据区 (注:Java8中已经移除了永久代,新加了一个叫做元数据区的native内存区)

类的生命周期:
     

   类的生命周期包括这几个部分,加载、连接、初始化、使用和卸载,其中前三部是类的加载的过程,如下图:

加载,查找并加载类的二进制数据,在Java堆中也创建一个java.lang.Class类的对象

连接,连接又包含三块内容:验证、准备、初始化。 1)验证,文件格式、元数据、字节码、符号引用验证; 2)准备,为类的静态变量分配内存,并将其初始化为默认值; 3)解析,把类中的符号引用转换为直接引用

初始化,为类的静态变量赋予正确的初始值

使用,new出对象程序中使用

卸载,执行垃圾回收
 

 Java对象创建过程

1.JVM遇到一条新建对象的指令时首先去检查这个指令的参数是否能在常量池中定义到一个类的符号引用。然后加载这个类(类加载过程在后边讲)

2.为对象分配内存。一种办法“指针碰撞”、一种办法“空闲列表”,最终常用的办法“本地线程缓冲分配(TLAB)”

3.将除对象头外的对象内存空间初始化为0

4.对对象头进行必要设置
 

对象分配规则:

        对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。

        大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。

        长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。

        动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。

        空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。
 

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

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

相关文章

如何在一台服务器上同时运行搭载JDK 8, JDK 17, 和 JDK 21的项目:终极指南

🐯 如何在一台服务器上同时运行搭载JDK 8, JDK 17, 和 JDK 21的项目:终极指南 🚀 摘要 在企业开发环境中,常常需要在同一台服务器上运行使用不同Java开发工具包(JDK)版本的多个项目。本文详细介绍如何在L…

报错import build constraints exclude all Go files in

好久没用fyne突然报错 报错import ...go-gl.. build constraints exclude all Go files in go-gl .. 检查gcc --version正常输出 检查gcc版本正常,路径正常。 尝试解决的方法, 1.重新安装依赖,不行 2.重新配置下载地址,不…

window平台C#实现软件升级功能(控制台)

window平台C#实现软件升级功能 之前用window窗体实现过一个升级功能,后来发现多个项目都需要升级功能,现改成可接收参数实现一种通用的exe.改用控制台方式实现这个升级功能,这样不仅实现了接收参数,升级程序体积也比原来的窗体形式…

河道采砂执法监管信息化平台:科技赋能,智慧监管

随着信息技术的飞速发展,信息化平台已经成为提升行业监管效率和水平的重要工具。河道采砂作为水利资源管理的重要环节,其执法监管同样需要与时俱进,利用先进技术手段提升监管效能。河道采砂执法监管信息化平台便是这一背景下的产物&#xff0…

从底层分析并详解SpringAOP底层实现

首先分析AOP的实现 首先切面(Advisor)由通知(Advice)和切点(Pointcut)组成 包括前置通知后置通知等等最终都会被转化为实现 MethodInterceptor 接口的环绕通知 先看一段代码了解一下是aop是怎么运作的 首先定义了两个类实现了MethodInterceptor接口&…

Unity HDRP Water Surface 水系统 基础教程

Unity HDRP Water Surface 水系统 基础教程 Unity Water SurfaceUnity 项目创建Unity Water Surface:Ocean(海洋)简介Ocean:Transform、GeneralOcean:Simulation(仿真模拟)Ocean:Sim…

C++之STL-String

目录 一、STL简介 1.1 什么是STL 1.2 STL的版本 1.3 STL的六大组件 ​编辑 1.4 STL的重要性 二、String类 2.1 Sting类的简介 2.2 string之构造函数 2.3 string类对象的容量操作 2.3.1 size() 2.3.2 length() 2.3.3 capacity() 2.3.4 empty() 2.3.5 clear() 2.3.6…

【IDEA】在IntelliJ IDEA中导入Eclipse项目:详细指南

IntelliJ IDEA和Eclipse是两款常用的集成开发环境(IDE),在软件开发中经常会遇到需要在它们之间迁移项目的情况。本文将重点介绍如何在IntelliJ IDEA中导入Eclipse项目,以帮助开发者顺利地迁移他们的项目,并在IntelliJ …

echarts 堆叠柱状图 顶部添加合计

堆叠有3个,后面加了一个对象显示顶部的数据, 其实主要的代码还是在series 的第四项,需要注意的是 series的第四项中的data需要为 data: [0, 0, 0] 顶部的统计才能显示出来 增加的代码如下 {name: 综合,type: bar,stack: total,label: {sh…

【Java框架】SpringMVC(三)——异常处理,拦截器,文件上传,SSM整合

目录 异常处理解释局部异常处理全局异常 拦截器拦截器介绍作用:拦截器和过滤器之间的区别拦截器执行流程代码实现补充 文件上传依赖配置MultipartResolver编写文件上传表单页APIMultipartFileFile.separator必须对上传文件进行重命名代码示例 SpringMVC文件上传流程多文件上传 …

AWS制作WordPress在国内外的利弊?

AWS作为全球领先的云计算服务供应商,为WordPress提供了强大且灵活的托管环境,使用AWS来搭建和运行WordPress无疑是个不错的选择。即便如此使用AWS制作还是会有些许利弊,九河云作为AWS的合作伙伴来为读者们仔细探讨AWS在WordPress的利弊。 利&…

学python的第十九天

网络通信和访问数据库 1.1 基本的网络知识 TCP/IP IP是低级的路由协议,它将数据拆分在许多小的数据包中,并通过网络将他们发送到某一特定地址,但无法保证所有包都抵达目的地,也不能保证包按顺序抵达 TCP(传输控制协议…

深度学习系列65:数字人openHeygen详解

1. 主流程分析 从inference.py函数进入,主要流程包括: 1) 使用cv2获取视频中所有帧的列表,如下: 2)定义Croper。核心代码为69行:full_frames_RGB, crop, quad croper.crop(full_frames_RGB)。…

Android MVVM架构 + Retrofit完成网络请求

关于Retrofit,这个应该不是一个很新颖的东西了,简单过一下吧 1.由Square公司开发,基于Type-safe的REST客户端。 2.使用注解来定义API接口,使得HTTP请求变得简洁且易于维护。 3.支持同步和异步请求,可与RxJava、Corouti…

【安卓13】解决带GMS编译报super分区空间不足错误

1、错误信息 2、解决方案 不同供应商修改分区大小的文件路径不一样,但是万变不离其宗,根据报错信息全局搜索关键词BOARD_SUPER_PARTITION_SIZE 这里以RK供应商和AML供应商修改为例: (1)RK改法: 根目录下…

全光谱灯对人体的危害?谨记全光谱灯选购要避开的四大套路

全光谱灯对人体的危害有多大?近年来网上关于护眼台灯对视力有害的言论有很多,引发了很多人空前的关注,事实上这未必是一件坏事,因为随着护眼台灯的热度持续上涨,市面上浑水摸鱼的行为增多了不少,有着不少劣…

STM32H7使用FileX库BUG,SD卡挂载失败

问题描述: 使用STM32H7ThreadXFileX,之前使用swissbit牌的存储卡可正常使用,最近项目用了金士顿的存储卡,发现无法挂载文件系统。 原因分析: 调试过程发现,关闭D-Cache可以挂载使用exfat文件系统。 File…

一文看够,植物线粒体基因组分析套路

线粒体堪称生命活动的“能量供给站”,植物线粒体是线粒体基因组研究中难度最高的,其基因组大小差异较大,100kb-10Mb,大部分由非编码DNA序列组成,且有许多同源序列,占基因组总长的2%-60%,基因间区…

制作github.io学术个人主页

制作如图的学术个人主页。About me - Xianwen Ling’s Blog 学术个人主页是一个学者展示个人学术成果和研究方向的重要工具。个人主页可以集中展示学者的研究论文、出版物、演讲和发布的项目等学术成果,这样其他人可以更方便地了解和评估学者的研究贡献。个人主页可…

Maven 安装及配置教程(Windows)【安装】

文章目录 一、 下载1. 官网下载2. 其它渠道 二、 安装三、 配置四、 验证五、 本地仓储配置六、 配置镜像七、 配置JDK八、完整配置九、常用命令十、IDEA 中配置 Maven1. 配置当前项目2. 配置新建 / 新打开 项目 软件 / 环境安装及配置目录 一、 下载 1. 官网下载 安装地址&a…