当前位置: 首页 > news >正文

学习笔记02——《深入理解Java虚拟机(第三版)》第三章

一、核心脉络:垃圾回收与内存分配策略

核心命题:JVM如何高效管理内存的分配与回收? 三大核心机制

  1. 对象存活判定(引用追踪 vs 可达性分析)

  2. 垃圾回收算法(标记-清除/复制/标记-整理/分代)

  3. 垃圾收集器实现(Serial/Parallel/CMS/G1等)


二、深度解析核心知识点

1. 对象存活判定

(1) 引用计数法(非JVM方案)
  • 原理:对象被引用时计数器+1,引用失效时-1,归零即回收

  • 致命缺陷:无法解决循环引用问题(A→B→A)

(2) 可达性分析算法(JVM实际方案)
  • GC Roots对象类型

    • 虚拟机栈局部变量表引用的对象

    • 方法区中类静态属性引用的对象

    • 方法区中常量引用的对象

    • 本地方法栈JNI引用的Native对象

    • 同步锁持有的对象(synchronized)

    • 内部引用(Class对象、异常对象、类加载器等)

  • 二次标记机制: 第一次标记后进入“缓刑”阶段,若未重写finalize()或已被调用过,则直接回收

2. 四大经典垃圾回收算法

算法核心思想优势缺陷
标记-清除标记存活对象,清除未标记区域实现简单内存碎片化,大对象分配困难
复制算法将内存分为两块,每次使用一块,存活对象复制到另一块无碎片,高效内存利用率仅50%
标记-整理标记存活对象后向一端移动,清理边界外内存无碎片,适合老年代移动对象开销大
分代收集基于对象的生命周期,将堆内存划为新生代和老年代;分别采用不同的回收方法。新生代(复制算法)、老年代(标记-清除/整理)针对性优化,平衡效率与空间需要处理跨代引用问题

3. 主流垃圾收集器对比(重点!)

收集器工作区域线程模式算法特点
Serial新生代单线程复制简单高效,Client模式默认,STW时间敏感场景慎用
ParNew新生代多线程复制Serial的多线程版本,需配合CMS使用
Parallel Scavenge新生代多线程复制吞吐量优先,适合后台计算型应用
CMS老年代并发标记-清除低延迟,四阶段流程(初始标记→并发标记→重新标记→并发清除),内存碎片问题显著
G1全堆并发+并行分区+标记-整理可预测停顿时间,将堆划分为Region,兼顾吞吐与延迟,JDK9默认
ZGC全堆并发染色指针+读屏障亚毫秒级停顿,TB级堆支持,JDK11引入

4. 内存分配策略

  • 对象优先在Eden分配:多数对象朝生夕死,Eden区采用复制算法

  • 大对象直接进老年代:避免在新生代反复复制(-XX:PretenureSizeThreshold参数控制)

  • 长期存活对象晋升:对象年龄计数器(-XX:MaxTenuringThreshold)

  • 空间分配担保:Minor GC前检查老年代剩余空间是否大于历次晋升对象平均大小

5.垃圾收集器的性能调优

(一)选择合适的垃圾收集器

根据应用的特点选择合适的垃圾收集器: • 低延迟需求:CMS或G1。 • 高吞吐量需求:Parallel或G1。 • 超大内存需求:ZGC。

(二)调整堆大小

通过-Xms和-Xmx参数合理配置堆内存大小,减少垃圾回收频率。例如:

-Xms512m -Xmx4g

(三)监控与分析

使用工具(如VisualVM、JStat、GC日志)监控垃圾回收行为,分析GC日志,优化配置。例如:

-XX:+PrintGCDetails -Xloggc:gc.log

 (四)调整垃圾收集器参数

根据垃圾收集器的特性,调整相关参数以优化性能。例如: • G1收集器:

-XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:MaxGCPauseMillis=200

 • CMS收集器:

-XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70

三、实战案例分析

(一)案例1:CMS收集器的调优

问题描述:某Web应用在高并发场景下,频繁触发Full GC,导致响应时间显著增加。

分析过程:

  1. 通过GC日志发现,老年代的内存使用率较高,CMS收集器的并发阶段耗时较长。

  2. 使用VisualVM监控内存使用情况,发现存在大量长生命周期的对象。

解决方案:

  1. 增加老年代的内存大小(-XX:MaxHeapSize)。

  2. 调整CMS收集器的触发阈值(-XX:CMSInitiatingOccupancyFraction=75)。

  3. 启用增量式并发收集(-XX:+CMSIncrementalMode)。

优化效果:调整后,Full GC的频率显著降低,应用响应时间恢复正常

(二)案例2:G1收集器的调优

问题描述:某大数据应用在运行过程中,频繁触发垃圾回收,导致停顿时间过长。

分析过程:

  1. 通过GC日志发现,G1收集器的Mixed GC阶段耗时较长。

  2. 使用JStat监控Region的使用情况,发现存在大量大对象。

解决方案:

  1. 增加堆内存大小(-Xmx)。

  2. 调整G1收集器的停顿时间目标(-XX:MaxGCPauseMillis=300)。

  3. 增加Region的大小(-XX:G1HeapRegionSize=32m)。

优化效果:调整后,垃圾回收的停顿时间显著降低,应用运行更加稳定。


四、高频面试问题总结(附答案要点)

1. 如何判断对象是否存活?

  • 可达性分析:通过GC Roots链是否可达,具体列举至少4种GC Roots类型

2. 四种引用类型的区别?

  • 强引用(Object obj = new Object()):宁可OOM也不回收

  • 软引用(SoftReference):内存不足时回收,适合缓存

  • 弱引用(WeakReference):下次GC必回收

  • 虚引用(PhantomReference):无法通过它访问对象,跟踪对象被回收的状态

3. CMS收集器的工作流程与优缺点?

  • 流程:初始标记(STW)→ 并发标记 → 重新标记(STW)→ 并发清除

  • 优点:低延迟

  • 缺点:内存碎片、CPU敏感、无法处理浮动垃圾

4. G1相比CMS的核心改进?

  • 分区模型:将堆划分为多个Region,避免全堆扫描

  • 可预测停顿:通过维护Region回收价值优先列表

  • 算法升级:整体标记-整理,局部复制算法避免碎片

5. 如何排查内存泄漏?

  • 步骤

    1. jps获取进程ID

    2. jstat -gcutil观察GC频率

    3. jmap -histo:live生成堆直方图

    4. jmap -dump导出堆转储文件

    5. MAT工具分析对象引用链


五、实战思考题

  1. 为什么新生代需要两个Survivor区? (答:解决复制算法空间浪费问题,单Survivor会导致每次复制后一半空间完全闲置)

  2. 为什么G1适合大堆场景? (答:Region划分可精准控制回收范围,避免全堆回收带来的长停顿)


延伸学习建议:结合JVM参数(-XX:+UseG1GC等)与GC日志分析工具(GCViewer)进行实践观测,理解不同收集器的行为差异。

相关文章:

  • goredis常见基础命令
  • 深度学习:基于Qwen复现DeepSeek R1的推理能力
  • 法线向量在3D机器视觉中的应用
  • C#初级教程(4)——流程控制:从基础到实践
  • 信息学奥赛一本通 1522:网络 | OpenJudge 百练 1144:Network
  • 算法每日一练 (4)
  • 【Winform】深入理解C#中的异常处理:以WinForms应用程序为例
  • GB28181协议下的RTP传输
  • Android Loader机制解析
  • MapReduce 读取 Hive ORC ArrayIndexOutOfBoundsException: 1024 异常解决
  • Excell 代码处理
  • kafka基本知识
  • Prompt Engineering的重要性
  • JAVAweb-JS基本数据类型,变量,DOM,pop,push函数,事件
  • 【Python爬虫(47)】探秘分布式爬虫性能:从测试到优化之路
  • 哈希表入门到精通:从原理到 Python 实现全解析
  • 洛谷P9242 [蓝桥杯 2023 省 B] 接龙数列
  • 【SpringBoot教程】SpringBoot整合Caffeine本地缓存及Spring Cache注解的使用
  • SSI用量子计算来玩AI
  • 策略模式Spring框架下开发实例
  • 如何购买企业黄页网站/有必要买优化大师会员吗
  • 报名入口网站建设/免费发外链平台
  • 兖州网站建设/湖州网站seo
  • 定制开发网站多少钱/网络推广公司服务内容
  • 一家专门做衣服的网站/百度关键词seo外包
  • 上海电商公司排名/安卓内核级优化神器