揭秘JVM垃圾回收机制全解析

JVM垃圾回收机制概述

垃圾回收(Garbage Collection, GC)是JVM自动管理内存的核心机制,负责回收不再使用的对象所占用的内存空间。通过标记-清除、复制、标记-整理等算法,JVM实现了高效的内存管理,避免了手动内存管理的复杂性和潜在错误。

垃圾回收的基本原理

JVM通过可达性分析(Reachability Analysis)判断对象是否存活。从GC Roots(如栈帧中的局部变量、静态变量等)出发,遍历对象引用链,未被引用的对象标记为可回收。常见的GC Roots包括:

  • 虚拟机栈中引用的对象
  • 方法区中静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI引用的对象

垃圾回收算法

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

  • 标记阶段:遍历所有GC Roots,标记存活对象
  • 清除阶段:回收未标记对象的内存
  • 缺点:产生内存碎片,可能触发Full GC

复制算法(Copying)

  • 将内存分为两块,每次使用其中一块
  • 存活对象复制到另一块内存,清空当前块
  • 优点:无内存碎片;缺点:内存利用率仅50%
  • 适用于新生代(Young Generation)回收

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

  • 标记阶段与标记-清除相同
  • 整理阶段将存活对象向内存一端移动
  • 优点:避免内存碎片;缺点:移动对象开销大
  • 适用于老年代(Old Generation)回收

分代收集策略

JVM将堆内存划分为不同代,采用不同的回收策略:

新生代(Young Generation)

  • 使用复制算法,分为Eden区和两个Survivor区(S0/S1)
  • 对象优先分配在Eden区,Minor GC后存活对象移至Survivor
  • 经历多次GC仍存活的对象晋升至老年代

老年代(Old Generation)

  • 存放长期存活对象和大对象
  • 采用标记-清除或标记-整理算法
  • 触发Major GC或Full GC时回收

永久代/元空间(Metaspace)

  • JDK8前为永久代,后改为元空间
  • 存储类元数据,使用本地内存

垃圾收集器实现

Serial收集器

  • 单线程工作,暂停所有应用线程(Stop-The-World)
  • 新生代使用复制算法,老年代使用标记-整理
  • 适用于客户端模式和小内存应用

Parallel Scavenge收集器

  • 多线程并行回收,注重吞吐量
  • 新生代使用复制算法,老年代使用标记-整理
  • 适合后台计算型应用

CMS收集器(Concurrent Mark-Sweep)

  • 以最短回收停顿时间为目标
  • 过程分为:
    1. 初始标记(STW)
    2. 并发标记
    3. 重新标记(STW)
    4. 并发清除
  • 缺点:产生内存碎片,并发模式失败时退化为Serial Old

G1收集器(Garbage-First)

  • 面向服务端应用,JDK9后默认收集器
  • 将堆划分为多个Region,优先回收价值最大(Garbage-First)的Region
  • 过程分为:
    1. 初始标记
    2. 并发标记
    3. 最终标记
    4. 筛选回收
  • 特点:可预测停顿时间,整体基于标记-整理,局部基于复制算法

内存分配与回收策略

  • 对象优先在Eden分配:多数对象生命周期短,适合新生代分配
  • 大对象直接进入老年代:避免在Eden和Survivor间大量复制
  • 长期存活对象进入老年代:对象年龄计数器达到阈值(默认15)
  • 动态年龄判定:Survivor中相同年龄对象总大小超过一半时,大于该年龄的对象直接进入老年代
  • 空间分配担保:Minor GC前检查老年代剩余空间是否足够,不足则触发Full GC

性能调优参数

  • -Xms / -Xmx:设置堆初始和最大大小
  • -Xmn:设置新生代大小
  • -XX:SurvivorRatio:设置Eden与Survivor区比例
  • -XX:NewRatio:设置新生代与老年代比例
  • -XX:MaxTenuringThreshold:设置对象晋升老年代的年龄阈值
  • -XX:+UseSerialGC:指定使用Serial收集器
  • -XX:+UseParallelGC:指定使用Parallel Scavenge收集器
  • -XX:+UseConcMarkSweepGC:指定使用CMS收集器
  • -XX:+UseG1GC:指定使用G1收集器

常见问题与解决方案

内存泄漏

  • 现象:GC后堆内存持续增长,最终OOM
  • 原因:对象被无意保留(如静态集合、未关闭资源)
  • 解决:使用内存分析工具(MAT、JProfiler)查找泄漏点

GC频繁

  • 现象:GC日志显示Young GC或Full GC频繁
  • 原因:新生代太小、对象过早晋升、大对象分配
  • 解决:调整新生代大小、优化对象生命周期

长时间停顿

  • 现象:GC日志显示STW时间过长
  • 原因:老年代过大、CMS并发模式失败
  • 解决:改用G1收集器、增加堆内存、优化老年代比例

监控与诊断工具

  • jstat:监控GC统计信息
    jstat -gcutil <pid> 1000
    
  • jmap:生成堆转储快照
    jmap -dump:format=b,file=heap.hprof <pid>
    
  • VisualVM:图形化监控GC活动
  • GC日志分析:添加参数-XX:+PrintGCDetails -Xloggc:gc.log

最佳实践

  • 根据应用特点选择合适收集器:低延迟选CMS/G1,高吞吐选Parallel
  • 避免创建过多短生命周期对象,减少Minor GC压力
  • 合理设置堆大小,避免频繁GC或OOM
  • 关注GC日志,定期分析性能瓶颈
  • 对大流量系统,进行压力测试验证GC配置

通过深入理解JVM垃圾回收机制,开发人员可以编写更高效的内存友好型代码,并针对特定应用场景优化GC性能,实现系统稳定性和吞吐量的平衡。

BbS.okacop010.info/PoSt/1120_487666.HtM
BbS.okacop011.info/PoSt/1120_546139.HtM
BbS.okacop012.info/PoSt/1120_293044.HtM
BbS.okacop013.info/PoSt/1120_696393.HtM
BbS.okacop014.info/PoSt/1120_730463.HtM
BbS.okacop015.info/PoSt/1120_302002.HtM
BbS.okacop016.info/PoSt/1120_315505.HtM
BbS.okacop017.info/PoSt/1120_505268.HtM
BbS.okacop018.info/PoSt/1120_558311.HtM
BbS.okacop019.info/PoSt/1120_206877.HtM
BbS.okacop010.info/PoSt/1120_211575.HtM
BbS.okacop011.info/PoSt/1120_560065.HtM
BbS.okacop012.info/PoSt/1120_882086.HtM
BbS.okacop013.info/PoSt/1120_852957.HtM
BbS.okacop014.info/PoSt/1120_481859.HtM
BbS.okacop015.info/PoSt/1120_716675.HtM
BbS.okacop016.info/PoSt/1120_628272.HtM
BbS.okacop017.info/PoSt/1120_853771.HtM
BbS.okacop018.info/PoSt/1120_165882.HtM
BbS.okacop019.info/PoSt/1120_680489.HtM
BbS.okacop020.info/PoSt/1120_135694.HtM
BbS.okacop021.info/PoSt/1120_580653.HtM
BbS.okacop022.info/PoSt/1120_033483.HtM
BbS.okacop023.info/PoSt/1120_077830.HtM
BbS.okacop024.info/PoSt/1120_247019.HtM
BbS.okacop025.info/PoSt/1120_599525.HtM
BbS.okacop026.info/PoSt/1120_033903.HtM
BbS.okacop027.info/PoSt/1120_066138.HtM
BbS.okacop028.info/PoSt/1120_506784.HtM
BbS.okacop029.info/PoSt/1120_994231.HtM
BbS.okacop020.info/PoSt/1120_636704.HtM
BbS.okacop021.info/PoSt/1120_286557.HtM
BbS.okacop022.info/PoSt/1120_953700.HtM
BbS.okacop023.info/PoSt/1120_153014.HtM
BbS.okacop024.info/PoSt/1120_359793.HtM
BbS.okacop025.info/PoSt/1120_847646.HtM
BbS.okacop026.info/PoSt/1120_862714.HtM
BbS.okacop027.info/PoSt/1120_396352.HtM
BbS.okacop028.info/PoSt/1120_695324.HtM
BbS.okacop029.info/PoSt/1120_425840.HtM
BbS.okacop020.info/PoSt/1120_001644.HtM
BbS.okacop021.info/PoSt/1120_779445.HtM
BbS.okacop022.info/PoSt/1120_278512.HtM
BbS.okacop023.info/PoSt/1120_278809.HtM
BbS.okacop024.info/PoSt/1120_313131.HtM
BbS.okacop025.info/PoSt/1120_634705.HtM
BbS.okacop026.info/PoSt/1120_462574.HtM
BbS.okacop027.info/PoSt/1120_679707.HtM
BbS.okacop028.info/PoSt/1120_921995.HtM
BbS.okacop029.info/PoSt/1120_902004.HtM

#牛客AI配图神器#

全部评论

相关推荐

14号一二面,15号三面,差不多一周后挂的,面经还是发出来吧,好像base北京还挂着前端的岗位,造福一下后来人被挂后自己分析了下,可能还是有个别八股不熟悉,就像三面被问的那个,以及其实对实习的项目深挖的不够,还有就是运气也不咋地吧哈哈,被挂了emo了挺久,现在也释怀了,命运给我什么我就接受什么吧【一面】1.js单线程还是多线程?为什么被设计成为单线程语言?单线程不能充分利用cpu的并发能力,设计成多线程不好吗?(我回答可能就是多个线程同时操作一个dom元素导致浏览器不知道咋办)2.既然这样,不可以加锁吗?(我回答可能跟浏览器调配各种进程资源的能力有关.......?)3.听说过web&nbsp;worker吗?4.和主线程最核心的区别?5.所以js还是单线程语言吗?(面试官说最完整的描述应该是:操作跟dom有关的线程是单线程,但是为了解决CPU密集型任务,他可以通过web&nbsp;worker来解决,但这个worker线程和主线程有能力上的区别)6.this指向输出题7.事件循环输出题8.能不能宏任务优先,微任务低优?9.服务端渲染有什么好处吗?(ssr不是比csr更快,只是渲染在哪做,但是渲染的那块时间也不会少,并没有优化性能)10.ssr为何有利于seo?11.webpack五要素12.loader和plugin的区别13.什么叫树摇14.让你实现一个plugin,必须实现哪个方法?15.webpack声明周期16.webpack在production的优化?(多线程,面试官说是在构建时的优化,应该答splitchunks)17.splitchunks有哪些好处18.vite比webpack快,最根本的点?(应该是答基于esm)19.为什么vite开发不全量打包是为何?(面试官说是因为webpack那时候浏览器还没有esm模块化)20.手撕无重复最长子串【二面】1.项目难点介绍2.koa2的洋葱模型是为什么(代码层面)?3.中间层维护?怎么确保中间层服务的稳定?(实习项目相关)4.多个接口调用,怎么并发执行?(promise.all,描述如何实现)5.怎么实现有最大请求数的并发控制?(异步调度器scheduler实现,手写)6.promise的then是返回新的promise还是原来的?总是返回一个新的实例。7.为什么promise的then/catch/finally可以链式调用?8.then里面可以return&nbsp;this吗?9.首屏可以有哪些优化手段?10.懒加载组件怎么做?11.打包完成之后是怎么懒加载的?浏览器请求下载这个单独的bundle的方式是什么?(不懂,这块不知道)12.settimeout怎么理解?13.webpack/vite热更新怎么做的?14.react组件间通信15.为何redux同步修改状态在reducer,异步操作在thunk中?(不知道,因为不可变更新吗)16.react的diff算法?【三面】1.你参加的那些比赛分别做了什么?2.研究方向是什么?3.为什么选择那个公司实习?(不知道怎么回答)4.讲一下小程序做的啥?5.taro设计的dsl,到支付宝/微信小程序/h5的dsl有看过吗?怎么设计的(dsl啥意思不知道,下来查了才知道原来就是让我解释taro的编译型跨端原理orz)6.请求层重构讲一下?(实习相关,重复请求拦截+支持主动取消请求)7.业务层主动取消是在什么情况下?(实习项目相关用户操作触发了请求但是用户又很快退出这个页面了)8.bff层做的什么?(实习项目相关)9.接口编排具体指的什么?(实习项目相关)10.bff用的什么启动?node还是express?或者pm2?11.node启动有做什么维护稳定?(我答错了,不是指和grpc的连接那块怎么提供稳定服务,这里面试官问的是怎么保证中间层服务的稳定性)12.做轻量化社交平台的契机?13.选react18的原因?(我大概从18的提升上说的,并发渲染还有和ssr的结合)14.在这个练习项目中,最大的收获?(验证自己的学习成果,提升技术掌握熟练度,以及接触一些新的技术比如nextjs、websocket)15.耗时比较久的是哪块?16.讲一下原型链17.类之间的继承,原型发挥了什么作用?(没答好,直接说了子类继承父类的原型需要手动写,但下来查了这是es5之前的,有了原型es6之后就不用手动写,super的调用就包含了原型的继承)18.事件循环讲讲?19.对未来半年到一年的职业发展?20.对自己的技术学习有什么规划?(我回答的跟业务深度契合的技术栈上深入学习)21.抛开业务层面的话,想学习什么技术?
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务