JVM 中的完整 GC 流程

一、引言

在 Java 应用程序的运行过程中,垃圾回收是一个至关重要的环节。它负责自动管理内存,回收不再被使用的对象,以确保应用程序的稳定运行。了解 JVM 中一次完整的 GC 流程对于优化 Java 应用的性能、减少内存占用以及避免内存泄漏至关重要。本文将深入探讨 JVM 中的 GC 流程。

二、JVM 内存结构概述

(一)堆内存

  1. 新生代(Young Generation)
    • Eden 区:新创建的对象首先分配在 Eden 区。
    • Survivor 区:分为 From Survivor 和 To Survivor 两个区域,用于存放经过一次 Minor GC 后仍然存活的对象。
  2. 老年代(Old Generation):存放经过多次 Minor GC 后仍然存活的对象。

(二)方法区(Metaspace)

存储类信息、常量、静态变量等数据。

(三)程序计数器、虚拟机栈和本地方法栈

用于存储线程的执行状态和局部变量等信息。

三、GC 类型

(一)Minor GC

  1. 触发条件
    • 当 Eden 区满时,触发 Minor GC。
  2. 作用范围
    • 主要清理新生代中的垃圾对象。

(二)Major GC/Full GC

  1. 触发条件
    • 老年代空间不足时触发 Major GC 或 Full GC。
    • 永久代(在 Java 8 后被 Metaspace 替代)空间不足时也可能触发 Full GC。
    • 显示调用 System.gc () 时可能触发 Full GC,但不建议在生产环境中使用。
  2. 作用范围
    • 清理整个堆内存,包括新生代和老年代。

四、Minor GC 流程

(一)标记阶段

  1. 可达性分析
    • 从根对象(如线程栈中的局部变量、静态变量等)开始,通过引用链遍历所有可达的对象。
    • 不可达的对象被标记为垃圾。
  2. 三色标记法
    • 白色:表示未被访问过的对象。
    • 灰色:表示对象已经被访问过,但它的引用还没有被完全处理。
    • 黑色:表示对象已经被访问过,并且它的引用也已经被完全处理。

(二)复制阶段

  1. 将 Eden 区和 From Survivor 区中存活的对象复制到 To Survivor 区。
  2. 如果对象的年龄达到一定阈值(默认是 15),则将其晋升到老年代。

(三)清理阶段

  1. 清理 Eden 区和 From Survivor 区中的垃圾对象。
  2. 将 From Survivor 区和 To Survivor 区互换角色,为下一次 Minor GC 做准备。

五、Major GC/Full GC 流程

(一)标记阶段

  1. 与 Minor GC 的标记阶段类似,采用可达性分析和三色标记法对整个堆内存中的对象进行标记。
  2. 由于老年代中的对象通常比较多,标记过程可能会比较耗时。

(二)整理阶段

  1. 对于老年代中的垃圾对象,进行清理。
  2. 可能会对存活的对象进行整理,以减少内存碎片。整理的方式可以是移动存活的对象,使它们连续存储。

(三)Metaspace 的清理(如果需要)

  1. 如果 Metaspace 空间不足,也可能触发 Full GC,此时会对 Metaspace 中的无用类信息等进行清理。

六、GC 触发条件的详细分析

(一)堆内存使用情况

  1. 新生代空间不足
    • 当 Eden 区和 Survivor 区中的对象占用空间超过一定比例时,触发 Minor GC。
    • 可以通过调整 JVM 参数来控制新生代的大小和比例,如 -Xmn 用于设置新生代的大小。
  2. 老年代空间不足
    • 当老年代中的对象占用空间超过一定比例时,触发 Major GC 或 Full GC。
    • 可以通过调整 JVM 参数来控制老年代的大小,如 -Xms 和 -Xmx 用于设置堆内存的初始大小和最大大小。

(二)对象的生命周期

  1. 对象的年龄增长
    • 对象在新生代中经过一次 Minor GC 后仍然存活,它的年龄会增加。当对象的年龄达到一定阈值时,会被晋升到老年代。
    • 可以通过调整 JVM 参数 -XX:MaxTenuringThreshold 来控制对象晋升到老年代的年龄阈值。
  2. 大对象直接进入老年代
    • 如果创建的对象占用空间较大,可能会直接进入老年代。可以通过调整 JVM 参数 -XX:PretenureSizeThreshold 来控制大对象的大小阈值。

(三)其他触发因素

  1. System.gc () 的调用
    • 在代码中显式调用 System.gc () 可能会触发 Full GC,但不建议在生产环境中使用,因为它会影响应用程序的性能。
  2. JVM 自身的策略
    • JVM 可能会根据一些内部策略触发 GC,如为了避免内存溢出等情况。

七、GC 算法详解

(一)标记 - 清除算法(Mark-Sweep)

  1. 算法原理
    • 标记阶段:通过可达性分析标记出所有存活的对象。
    • 清除阶段:清理所有未被标记的对象,释放内存空间。
  2. 优缺点
    • 优点:实现简单。
    • 缺点:会产生内存碎片,可能导致后续分配大对象时需要进行额外的整理操作。

(二)标记 - 整理算法(Mark-Compact)

  1. 算法原理
    • 标记阶段:与标记 - 清除算法相同。
    • 整理阶段:将所有存活的对象移动到一端,然后清理另一端的垃圾对象,从而避免内存碎片的产生。
  2. 优缺点
    • 优点:不会产生内存碎片。
    • 缺点:整理过程比较耗时,可能会影响应用程序的性能。

(三)复制算法(Copying)

  1. 算法原理
    • 将内存分为两块相等的区域,如新生代中的 Eden 区和 Survivor 区。当进行垃圾回收时,将存活的对象复制到另一块区域,然后清理原来的区域。
  2. 优缺点
    • 优点:实现简单,不会产生内存碎片。
    • 缺点:需要双倍的内存空间,当对象存活率较高时,复制操作会比较耗时。

八、实际案例分析

(一)案例背景

假设有一个 Java 应用程序,在运行过程中出现了频繁的 Full GC,导致应用程序性能下降。

(二)问题分析

  1. 通过监控工具(如 JVisualVM、jstat 等)观察堆内存的使用情况,发现老年代空间不足是触发 Full GC 的主要原因。
  2. 进一步分析发现,应用程序中存在一些大对象的创建,这些大对象直接进入老年代,导致老年代空间快速增长。
  3. 同时,应用程序中的某些对象的生命周期较长,经过多次 Minor GC 后仍然存活,最终晋升到老年代,也加剧了老年代空间的压力。

(三)解决方案

  1. 调整 JVM 参数
    • 增大堆内存的大小,如 -Xms 和 -Xmx,可以缓解老年代空间不足的问题,但要注意不要设置得过大,以免导致系统资源浪费。
    • 调整新生代和老年代的比例,如 -XX:NewRatio,可以适当增大新生代的空间,减少对象晋升到老年代的频率。
    • 调整对象晋升到老年代的年龄阈值,如 -XX:MaxTenuringThreshold,可以根据应用程序的实际情况适当降低年龄阈值,避免对象过早晋升到老年代。
  2. 优化对象创建
    • 避免创建不必要的大对象,如果确实需要创建大对象,可以考虑采用分块处理的方式,减少大对象对老年代的压力。
  3. 对象生命周期管理
    • 对于生命周期较长的对象,可以考虑采用对象池等技术,避免频繁地创建和销毁对象,减少对象晋升到老年代的机会。

九、GC 优化策略

(一)合理设置 JVM 参数

  1. 根据应用程序的特点和需求,合理设置堆内存的大小、新生代和老年代的比例、对象晋升年龄阈值等参数。
  2. 可以通过压力测试和性能监控来调整 JVM 参数,找到最适合应用程序的参数组合。

(二)对象生命周期管理

  1. 尽量减少不必要的对象创建,避免创建大量短期存活的对象,减少 Minor GC 的频率。
  2. 对于生命周期较长的对象,可以采用对象池等技术进行管理,提高对象的复用率。

(三)避免内存泄漏

  1. 及时释放不再使用的对象引用,避免内存泄漏。
  2. 对资源的使用(如数据库连接、文件流等)要及时关闭,防止资源泄漏导致内存占用过高。

(四)选择合适的 GC 算法

  1. 根据应用程序的特点选择合适的 GC 算法。例如,如果应用程序对响应时间要求较高,可以选择并发收集器;如果应用程序对吞吐量要求较高,可以选择并行收集器。
  2. 在 Java 8 及以上版本中,可以使用 G1 收集器,它在兼顾吞吐量和响应时间方面表现较好。

十、总结

JVM 中的垃圾回收是一个复杂而重要的过程。了解一次完整的 GC 流程对于优化 Java 应用程序的性能至关重要。通过合理设置 JVM 参数、管理对象生命周期、避免内存泄漏以及选择合适的 GC 算法,可以有效地减少 GC 的频率和时间,提高应用程序的性能和稳定性。

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

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

相关文章

通过投毒Bingbot索引挖掘必应中的存储型XSS

简介 在本文中,我将讨论如何通过从外部网站对Bingbot进行投毒,来在Bing.com上实现持久性XSS攻击。 什么是存储型或持久性XSS?存储型攻击指的是将恶意脚本永久存储在目标服务器上,例如数据库、论坛、访问日志、评论栏等。受害者在…

84.7k Star!Excalidraw:开源的在线白板工具,具备手绘风格和实时协作功能

❤️ 如果你也关注大模型与 AI 的发展现状,且对大模型应用开发非常感兴趣,我会快速跟你分享最新的感兴趣的 AI 应用和热点信息,也会不定期分享自己的想法和开源实例,欢迎关注我哦! 🥦 微信公众号&#xff…

让Git走代理

有时候idea提交代码或者从github拉取代码,一直报错超时或者:Recv failure: Connection was reset,下面记录一下怎么让git走代理从而访问到github。 1.打开梯子 2.打开网络和Internet设置 3.设置代理 记住这个地址和端口 4.打开git bash终端 输入以下内容 git c…

CSS:导航栏三角箭头

用CSS实现导航流程图的样式。可根据自己的需求进行修改,代码精略的写了一下。 注:场景一和场景二在分辨率比较低的情况下会有一个1px的缝隙不太优雅,自行处理。有个方法是直接在每个外面包一个DIV,用动态样式设置底色。 场景一、…

第4章-计划 4.3 订计划、勤跟踪、要闭环

4.3 订计划、勤跟踪、要闭环 1.制订好的第一版计划先要基线化,确保有据可依2.计划要监督执行,发现延期时要“喊出来”3.计划要赶得上变化4.资源保障是计划能够执行的依赖 坚定执行制订好的计划,监督执行效果,计划产生偏差时及时制…

在 WPF 中,如何实现数据的双向绑定?

在 WPF 中,数据绑定是一个非常重要的特性,它允许 UI 与数据源之间自动同步。双向绑定是一种常见的绑定方式,当数据源更新时,UI 会自动更新;同样,当 UI 中的元素(如文本框)发生改变时…

Java面向对象编程进阶之包装类

Java面向对象编程进阶之包装类 一、为什么要使用包装类二、掌握基本数据类型与包装类之间的转换1、为什么需要转换?2、如何转换? 三、String与基本数据类型、包装类之间的转换1、案例2、特别注意 一、为什么要使用包装类 为了使得基本类型的数据变量具备…

基于Spring Boot与Redis的令牌主动失效机制实现

目录 前言1. 项目结构和依赖配置1.1 项目依赖配置1.2 Redis连接配置 2. 令牌主动失效机制的实现流程2.1 登录成功后将令牌存储到Redis中2.2 使用拦截器验证令牌2.3 用户修改密码后删除旧令牌 3. Redis的配置与测试4. 可能的扩展与优化结语 前言 在现代Web系统中,用…

yolov8-cls的onnx与tensorrt推理

本文不生产技术,只做技术的搬运工! 前言 最近需要使用yolov8-cls进行模型分类任务,但是使用ultralytics框架去部署非常不方便,因此打算进行onnx或者tensorrt去部署,查看了很多网上的帖子,并没有发现有完整复现yolov8-cls前处理(不需要后处理)的"轮子",通过自己debug…

Acrobat Pro DC 2023(pdf免费转化word)

所在位置 通过网盘分享的文件:Acrobat Pro DC 2023(64bit).tar 链接: https://pan.baidu.com/s/1_m8TT1rHTtp5YnU8F0QGXQ 提取码: 1234 --来自百度网盘超级会员v4的分享 安装流程 打开安装所在位置 进入安装程序 找到安装程序 进入后点击自定义安装,这里…

VMware和CentOS 7.6 Linux操作系统的安装使用

1. 安装VMware 安装VMware之前,有些电脑是需要去BIOS里修改设置开启cpu虚拟化设备支持才能安装。如果运气不好在安装过程中安装不了的话就自行百度吧。 打开 VMware 的官网: https://www.vmware.com/ 点击 product,往下滑找到 see desktop hypeerviso…

手把手教你:如何从零开始实施一套OA办公系统!

很多朋友都吐槽说公司的各种各样的信息啊文件啊越积越多,导致管理起来越来越麻烦。早就跟大家说过,尤其是在提高工作效率、优化资源配置和促进信息共享方面,OA(办公自动化)系统发挥着不可替代的作用,早安排…

网页web无插件播放器EasyPlayer.js播放器返回错误 Incorrect response MIME type 的解决方式

在使用EasyPlayer.js播放器进行视频流播放时,尤其是在SpringBoot环境中部署静态资源时,可能会遇到“Incorrect response MIME type”的错误,这通常与WebAssembly(WASM)文件的MIME类型配置有关。 WASM是一种新的代码格式…

element-plus <el-date-picker>日期选择器踩坑!!!!

我怎么一上午踩两个坑&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff08;大声bb&#xff09; 原来的vue2老项目是这样写的 <el-form-item label"时间" prop"time"><el-date-pickerv-model"addForm.time"typ…

# 如何查看 Ubuntu 版本?

如何查看 Ubuntu 版本&#xff1f; 要查看‌Ubuntu版本&#xff0c;你可以通过以下几种方法&#xff1a; 1. 使用‌lsb_release 命令‌查看 使用 lsb_release -a 命令可以查看Ubuntu的详细版本信息&#xff0c;包括发行版ID、版本号以及版本代号。‌ ‌### 2、查看 /etc/is…

常用的生物医药专利查询数据库及网站(很全!)

生物医药专利信息检索是药物研发前期不可或缺的一步&#xff0c;通过对国内外生物医药专利网站信息查询&#xff0c;可详细了解其专利技术&#xff0c;进而有效降低药物研发过程中的风险。 目前主要使用的生物医药专利查询网站分为两大类&#xff0c;一个是免费生物医药专利查询…

第四节-OSI-网络层

数据链路层&#xff1a;二层--MAC地址精确定位 Ethernet 2&#xff1a; 报头长度&#xff1a;18B 携带的参数&#xff1a;D MAC /S MAC/TYPE(标识上层协议)/FCS 802.3 报头长度&#xff1a;26B 携带的参数&#xff1a;D MAC/S MAC/LLC(标识上层协议)/SNAP&#xff08;标识…

Python数据分析NumPy和pandas(二十七、数据可视化 matplotlib API 入门)

数据可视化或者数据绘图是数据分析中最重要的任务之一&#xff0c;是数据探索过程的一部分&#xff0c;数据可视化可以帮助我们识别异常值、识别出需要的数据转换以及为模型生成提供思考依据。对于Web开发人员&#xff0c;构建基于Web的数据可视化显示也是一种重要的方式。Pyth…

【前端】深入浅出 - TypeScript 的详细讲解

TypeScript 是一种静态类型编程语言&#xff0c;它是 JavaScript 的超集&#xff0c;添加了类型系统和编译时检查。TypeScript 的主要目标是提高大型项目的开发效率和可维护性。本文将详细介绍 TypeScript 的核心概念、语法、类型系统、高级特性以及最佳实践。 1. TypeScript…

查询DBA_FREE_SPACE缓慢问题

这个是一个常见的问题&#xff0c;理论上应该也算是一个bug&#xff0c;在oracle10g&#xff0c;到19c&#xff0c;我都曾经遇到过&#xff1b;今天在给两套新建的19C RAC添加监控脚本时&#xff0c;又发现了这个问题&#xff0c;在这里记录一下。 Symptoms 环境&#xff1a;…