JVM_垃圾收集器详解

news2024/11/29 1:45:04

1、 前言

JVM就是Java虚拟机,说白了就是为了屏蔽底层操作系统的不一致而设计出来的一个虚拟机,让用户更加专注上层,而不用在乎下层的一个产品。这就是JVM的跨平台,一次编译,到处运行。
而JVM中的核心功能其实就是自动化的垃圾回收机制。

在Java中你使用对象,使用内存,不用担心回收,只管new对象就行了,不用管垃圾的回收。
因为Java当中是自动化的垃圾回收机制。JVM有专门的垃圾回收器,把垃圾回收这件事给干了。

2、分代收集理论

当前虚拟机的垃圾收集都采用分代收集算法,根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
新生代:每次收集都会有大量对象(近99%)死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。就比如新生代中的 S0 和 S1 区域。

老年代:对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。

PS:标记-清除”或“标记-整理”算法会比复制算法慢10倍以上。

2.1、垃圾收集算法

标记-复制算法

标记-复制算法是把内存分为大小相等的两块,每次使用其中的一块,当这块内存使用完以后,就会把还存活的对象放到另外一块内存中去,清理刚才使用到的那块空间。分为标记和复制两个阶段:

第一阶段:标记;就是根据Gc Roots标记存活的对象。
第二阶段:复制;把存活的对象复制到另外一块内存中。
缺点:会浪费多余的存储空间。

2.2、标记-清除算法

标记-清除算法分为标记和清除两个阶段:
第一阶段:标记;就是根据Gc Roots标记存活的对象。
第二阶段:清除;统一回收未被标记的对象。

缺点:
效率问题 (如果需要标记的对象太多,效率不高) ;
空间问题(标记清除后会产生大量不连续的碎片)。

 2.3、标记-整理算法

标记-整理算法是根据老年代的特点设计出的一种标记算法。他的标记过程和标记清除算法一样的,后续不同的是,它会先把所有存活的对象规整的移动到一起,然后把边界外的对象统一回收。

3、垃圾回收中的STW

对于Java项目来说,JVM进行垃圾收集会有一个很大的问题,就是STW(Stop The World)。
就是在垃圾回收的时候会把应用线程(项目中运行的线程)给停止,然后进行垃圾回收,如果STW的时间过程,用户就会感觉到明显的卡顿现象。

3.1、STW带来的问题

1)安卓手机系统的卡顿
Google 主导的 Android 系统需要解决的一大问题就是显示卡顿问题,通过对 GC 算法的不断演进,停顿时间控制在几个ms 级别。所以这也是Android与苹果IOS系统竞争的一大利器。
2)证券交易系统的实时性
证券交易系统的实时性要求很高,一般都是需要低卖高卖,差之毫厘谬以千里,如果STW的时间很长,到达几秒钟的级别,这几秒钟后的市场完全不同了。所以用Java来做证券系统,STW的时间越短越好。

3.2、垃圾收集器的发展

为了满足不同的业务场景,Java的GC算法和垃圾收集器都在不同的迭代,对于这些延迟敏感的应用来说,GC停顿已经成为了阻碍Java发展的一大顽疾。

近些年来,服务器的性能越来越好,各种应用可以使用的堆内存也越来越大,其实垃圾收集器的发展都是为了解决STW的停顿时间而一直迭代。为了让STW的停顿时间也跟随着堆大小的增长而不呈现指数级的增长而努力,推出了一系列垃圾收集器。

4、垃圾收集器

如果说垃圾回收算法是内存收回的理论,那么垃圾收集器就是内存回收的具体实现。
虽然我们对各个收集器进行比较,但并非为了挑选出一个最好的收集器。因为直到现在为止还没有最好的垃圾收集器出现,更加没有万能的垃圾收集器, 我们能做的就是根据具体应用场景选择适合自己的垃圾收集器 。

4.1、单线程垃圾收集器

1)Serial

Serial(串行)垃圾收集器,一看名字就知道它是一个单线程收集器。它的单线程的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾手机工作,更重要的是它在进行垃圾手机工作的时候还必须暂停其他的所有工作线程(STW),直到它收集结束。

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

Serial 虽然是单线程,STW的时间有点长,但是它简单且高效(与其它垃圾收集器相比),它没有线程交互的开销,自然而然的可以获得很高的单线程收集效率。

参数设置:-XX:+UseSerialGC(年轻代)  -XX:+UseSerialOldGC(老年代)

2)Serial Old
Serial Old收集器是Serial收集器的老年代版本,它同样是单线程收集器。
两大用途:
一种用途是在JDK1.5 以及以前的版本中与Parallel Scavenge收集器搭配使用。
一种用途是作为CMS收集器的后备方案。

4.2、多线程垃圾收集器

1)Parallel Scavenge

Parallel收集器是Serial收集器的多线程版本,除了使用多线程垃圾收集以外,其余和Serial收集器类似。默认的收集线程数跟cpu核数相同,当然也可以用参数(-XX:ParallelGCThreads)指定收集线程数,但是一般不推荐修改。

Parallel Scavenge收集器关注点是吞吐量(高效率的利用CPU)。所谓吞吐量就是CPU中用于运行用户代码的时间与CPU总消耗时间的比值。

新生代采用标记-复制算法,老年代采用标记-整理算法。参数设置:-XX:+UseParallelGC(年轻代),-XX:+UseParallelOldGC(老年代)

2)Parallel Old
Parallel Old收集器是Parallel Scavenge收集器的老年代版本。
使用多线程和“标记-整理”算法。在注重吞吐量以及 CPU资源的场合,都可以优先考虑 Parallel Scavenge收集器和Parallel Old收集器(JDK8默认的新生代和老年代收集器)。

3)ParNew

ParNew收集器其实跟Parallel收集器很类似,区别主要在于它可以和CMS收集器配合使用。
新生代采用标记-复制算法,老年代采用标记-整理算法。
参数设置:-XX:+UseParNewGC

4.3、多线程+并发收集器

1)CMS
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体 验的应用上使用,它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。
从它的名字中可以看出它是一种 “标记-清除” 算法的实现

GC步骤:

初始标记(STW):暂停所有的其它线程,期间会STW,并记录GC Roots直接能引用的对象,速度很快。
并发标记:并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对象图的过程, 这个过程耗时较长但 是不需要停顿用户线程, 可以与垃圾收集线程一起并发运行。因为用户程序继续运行,可能会有导致已经标记过的对象状态发生改变。
重新标记(STW):重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短。主要用到三色标记里的增量更新算法做重新标记。
并发清理:开启用户线程,同时GC线程开始对未标记的区域做清扫。这个阶段如果有新增对象会被标记为黑色不做任何处理。
并发重置:重置本次GC过程中的标记数据。
优点:并发收集、低停顿。

缺点:
对CPU资源敏感(会和服务抢资源);
无法处理浮动垃圾(在并发标记和并发清理阶段又产生垃圾,这种浮动垃圾只能等到下一次gc再清理了);
它使用的回收算法-“标记-清除”算法会导致收集结束时会有大量空间碎片产生,当然通过参数(- XX:+UseCMSCompactAtFullCollection)可以让jvm在执行完标记清除后再做整理 。
执行过程中的不确定性,会存在上一次垃圾回收还没执行完,然后垃圾回收又被触发的情况,特别是在并 发标记和并发清理阶段会出现,一边回收,系统一边运行,也许没回收完就再次触发full gc,也就是"concurrent mode failure",此时会进入STW,用serial old垃圾收集器来回收。

核心参数设置:
参数 含义

-XX:+UseConcMarkSweepGC	启用CMS
-XX:ConcGCThreads	并发的GC线程数
-XX:+UseCMSCompactAtFullCollection	FullGC之后做压缩整理(减少碎片)
-XX:CMSFullGCsBeforeCompaction	多少次FullGC之后压缩一次,默认是0,代表每次FullGC后都会压缩一次
-XX:CMSInitiatingOccupancyFraction	当老年代使用达到该比例时会触发FullGC(默认是92,这是百分比)
-XX:+UseCMSInitiatingOccupancyOnly	
只使用设定的回收阈值
(-XX:CMSInitiatingOccupancyFraction设定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整 
-XX:+CMSScavengeBeforeRemark	在CMS GC前启动一次minor gc,目的在于减少老年代对年轻代的引 用,降低CMS GC的标记阶段时的开销,一般CMS的GC耗时 80%都在标记阶段
-XX:+CMSParallellnitialMarkEnabled	表示在初始标记的时候多线程执行,缩短STW
-XX:+CMSParallelRemarkEnabled	在重新标记的时候多线程执行,缩短STW

4.4、G1收集器

G1垃圾收集器的工作原理和特性‌:

G1垃圾收集器是一种面向服务器的垃圾收集器,它将堆划分为多个大小相等的独立区域(Region),这些Region可以是年轻代或老年代。G1保留了年轻代和老年代的概念,但它们不再是物理隔阂,而是Region的集合。G1通过监视应用程序的行为和垃圾收集暂停信息来建立相关成本模型,以实现可预测的暂停时间目标。它采用分步递增和并行的方式来执行空间回收,以缩短停顿时间‌。

大内存应用‌:G1垃圾收集器适用于堆大小约为6GB或更大的应用程序。当堆大小超过50%的Java堆内存被实时数据占用时,G1能够提供更好的性能‌。

多处理器机器‌:G1垃圾收集器特别适合配备多颗处理器的服务器,因为它能够利用多核处理器的优势,实现高效的垃圾收集‌。

需要稳定且可预测的暂停时间‌:G1垃圾收集器旨在实现稳定的暂停时间目标,通常不超过0.5秒,这对于需要低延迟的应用程序非常重要‌。

对象分配和晋升速率变化显著‌:在堆中,对象分配和晋升的速率可能会随时间显著变化,G1能够适应这种变化,提供更好的性能‌。

存在大量碎片‌:当堆中存在大量碎片时,G1能够通过分步递增和并行的方式来执行空间回收,减少碎片化对性能的影响‌。

使用G1垃圾收集器的命令行参数‌:

-XX:+UseG1GC:显式启用G1垃圾收集器。

-XX:G1HeapRegionSize:手动指定Region的大小。

-XX:G1NewSizePercent:设置新生代初始占比。

-XX:G1MaxNewSizePercent:调整新生代的最大占比。

这些参数可以帮助用户根据具体需求调整G1垃圾收集器的行为,以优化应用程序的性能和暂停时间‌。

4.5、ZGC

jdk11 低延迟,浮动垃圾多,适合几百G 以上

5 总结

本章主要讲了JVM中垃圾收集器的发展,从单线程到多线程,再到GC线程和用户线程并发收集的垃圾收集器。
如何选择垃圾收集器:
优先调整堆的大小让服务器自己来选择
如果内存小于100M,使用串行收集器
如果是单核,并且没有停顿时间的要求,串行或JVM自己选择
如果允许停顿时间超过1秒,选择并行或者JVM自己选
如果响应时间最重要,并且不能超过1秒,使用并发收集器
4G以下可以用parallel,4-8G可以用ParNew+CMS,8G以上可以用G1,几百G以上用ZGC。

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

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

相关文章

若依框架部署在网站一个子目录下(/admin)问题(

部署在子目录下首先修改vue.config.js文件: 问题一:登陆之后跳转到了404页面问题,解决办法如下: src/router/index.js 把404页面直接变成了首页(大佬有啥优雅的解决办法求告知) 问题二:退出登录…

BERT解析

BERT项目 我在BERT添加注释和部分推理代码 main.py vocab WordVocab.load_vocab(args.vocab_path)#加载vocab那么这个加载的二进制是什么呢? 1. 加载数据集 继承关系:TorchVocab --> Vocab --> WordVocab TorchVocab 该类主要是定义了一个词…

连接共享打印机0X0000011B错误多种解决方法

打印机故障一直是一个热门话题,特别是共享打印机0x0000011b错误特别头疼,有很多网友经常遇到共享打印机0x0000011b错误。0x0000011b有更新补丁导致的、有访问共享打印机服务异常、有访问共享打印机驱动异常等问题导致的,针对共享打印机0x0000…

spring +fastjson 的 rce

前言 众所周知&#xff0c;spring 下是不可以上传 jsp 的木马来 rce 的&#xff0c;一般都是控制加载 class 或者 jar 包来 rce 的&#xff0c;我们的 fastjson 的高版本正好可以完成这些&#xff0c;这里来简单分析一手 环境搭建 <dependency><groupId>org.spr…

jeecgbootvue2重新整理数组数据或者添加合并数组并遍历背景图片或者背景颜色

想要实现处理后端返回数据并处理&#xff0c;添加已有静态数据并遍历快捷菜单背景图 遍历数组并使用代码 需要注意&#xff1a; 1、静态数组的图片url需要的格式为 require(../../assets/b.png) 2、设置遍历背景图的代码必须是: :style"{ background-image: url( item…

15分钟做完一个小程序,腾讯这个工具有点东西

我记得很久之前&#xff0c;我们都在讲什么低代码/无代码平台&#xff0c;这个概念很久了&#xff0c;但是&#xff0c;一直没有很好的落地&#xff0c;整体的效果也不算好。 自从去年 ChatGPT 这类大模型大火以来&#xff0c;各大科技公司也都推出了很多 AI 代码助手&#xff…

jenkins 2.346.1最后一个支持java8的版本搭建

1.jenkins下载 下载地址&#xff1a;Index of /war-stable/2.346.1 2.部署 创建目标文件夹&#xff0c;移动到指定位置 创建一个启动脚本&#xff0c;deploy.sh #!/bin/bash set -eDATE$(date %Y%m%d%H%M) # 基础路径 BASE_PATH/opt/projects/jenkins # 服务名称。同时约定部…

3D建筑模型的 LOD 规范

LOD&#xff08;细节层次&#xff09; 是3D城市建模中用于表示建筑模型精细程度的标准化描述不同的LOD适用于不同的应用场景 LOD是3D建模中重要的分级标准&#xff0c;不同层级适合不同精度和用途的需求。 从LOD0到LOD4&#xff0c;细节逐渐丰富&#xff0c;复杂性和精度也逐…

解锁 Vue 项目中 TSX 配置与应用简单攻略

在 Vue 项目中配置 TSX 写法 在 Vue 项目中使用 TSX 可以为我们带来更灵活、高效的开发体验&#xff0c;特别是在处理复杂组件逻辑和动态渲染时。以下是详细的配置步骤&#xff1a; 一、安装相关依赖 首先&#xff0c;我们需要在命令行中输入以下命令来安装 vitejs/plugin-v…

【UE5 C++课程系列笔记】04——创建可操控的Pawn

根据官方文档创建一个可以控制前后左右移动、旋转视角、缩放视角的Pawn 。 步骤 一、创建Pawn 1. 新建一个C类&#xff0c;继承Pawn类&#xff0c;这里命名为“PawnWithCamera” 2. 在头文件中申明弹簧臂、摄像机和静态网格体组件 3. 在源文件中引入组件所需库 在构造函数…

多目标优化算法——多目标粒子群优化算法(MOPSO)

Handling Multiple Objectives With Particle Swarm Optimization&#xff08;多目标粒子群优化算法&#xff09; 一、摘要&#xff1a; 本文提出了一种将帕累托优势引入粒子群优化算法的方法&#xff0c;使该算法能够处理具有多个目标函数的问题。与目前其他将粒子群算法扩展…

HTML5好看的音乐播放器多种风格(附源码)

文章目录 1.设计来源1.1 音乐播放器风格1效果1.2 音乐播放器风格2效果1.3 音乐播放器风格3效果1.4 音乐播放器风格4效果1.5 音乐播放器风格5效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&…

通用网络安全设备之【防火墙】

概念&#xff1a; 防火墙&#xff08;Firewall&#xff09;&#xff0c;也称防护墙&#xff0c;它是一种位于内部网络与外部网络之间的网络安全防护系统&#xff0c;是一种隔离技术&#xff0c;允许或是限制传输的数据通过。 基于 TCP/IP 协议&#xff0c;主要分为主机型防火…

c++趣味编程玩转物联网:基于树莓派Pico控制有源蜂鸣器

有源蜂鸣器是一种简单高效的声音输出设备&#xff0c;广泛应用于电子报警器、玩具、计时器等领域。在本项目中&#xff0c;我们结合树莓派Pico开发板&#xff0c;通过C代码控制有源蜂鸣器发出“滴滴”声&#xff0c;并解析其中涉及的关键技术点和硬件知识。 一、项目概述 1. 项…

jar包打成exe安装包

打包exe并设置管理员权限 前言打包可执行文件exe准备jre环境运行exe4j并配置 设置执行文件exe管理员权限设置打包工具管理员权限打包exe安装包创建脚本打包 前言 准备安装包&#xff1a; jar包&#xff1a;自己的程序&#xff1b;exe4j&#xff1a;将jar打包可执行的exe&…

NAT:连接私有与公共网络的关键技术(4/10)

一、NAT 的工作原理 NAT 技术的核心功能是将私有 IP 地址转换为公有 IP 地址&#xff0c;使得内部网络中的设备能够与外部互联网通信。其工作原理主要包括私有 IP 地址到公有 IP 地址的转换、端口号映射以及会话表维护这几个步骤。 私有 IP 地址到公有 IP 地址的转换&#xff1…

多模态大型语言模型(MLLM)综述

目录 多模态大语言模型的基础 长短期网络结构(LSTM) 自注意力机制 基于Transformer架构的自然语言处理模型 多模态嵌入概述 多模态嵌入关键步骤 多模态嵌入现状 TF-IDF TF-IDF的概念 TF-IDF的计算公式 TF-IDF的主要思路 TF-IDF的案例 训练和微调多模态大语言模…

学习ASP.NET Core的身份认证(基于Cookie的身份认证3)

用户通过验证后调用HttpContext.SignInAsync函数将用户的身份信息保存在认证Cookie中,以便后续的请求可以验证用户的身份,该函数原型如下所示&#xff0c;其中properties参数的主要属性已在前篇文章中学习&#xff0c;本文学习scheme和principal的意义及用法。 public static …

C++设计模式-模板模式,Template Method

动机&#xff08;Motivation&#xff09; 在软件构建过程中&#xff0c;对于某一项任务&#xff0c;它常常有稳定的整体操作结构&#xff0c;但各个子步骤却有很多改变的需求&#xff0c;或者由于固有的原因&#xff08;比如框架与应用之间的关系&#xff09;而无法和任务的整…

Jenkins流水线 Allure JUnit5 自动化测试

目录 一、Jenkins Allure配置 1.1 安装Allure插件 1.2 安装Allure工具 1.3 配置测试报告路径 1.4 JenkinsFile 二、Jenkins 邮箱配置 2.1 安装Email Extension Plugin插件 2.2 邮箱配置 2.3 JenkinsFile 三、项目pom.xml 配置 3.1 引入allure-junit5依赖 3.2 引入m…