拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Java垃圾回收GC核心原理:标记清除、复制、标记整理算法详解【万字干货+代码实战+调优解法】

Java垃圾回收GC核心原理标记清除、复制、标记整理算法详解【万字干货代码实战调优解法】**标签**Java GC、JVM调优、垃圾回收算法、标记清除、复制算法、标记整理、内存碎片、STW**简介**本文深度剖析Java三大核心垃圾回收算法从底层原理、执行流程、源码模拟、优缺点、适用场景全方位拆解附带大量可运行Java实战代码、问题解法、性能优化方案同时对比各算法落地差异解决开发中GC卡顿、内存溢出、碎片过多等核心问题适合JVM进阶、性能调优学习与面试复盘。一、GC前置核心基础必看1.1 什么是垃圾回收GCGCGarbage Collection垃圾回收是Java虚拟机自动内存管理机制无需开发者手动申请、释放堆内存JVM会自动识别内存中无效垃圾对象回收其占用内存避免内存泄漏、内存溢出问题。核心目标自动回收无效对象内存、减少内存碎片、降低STW停顿时间、提升内存利用率。1.2 垃圾判定核心可达性分析算法Java不采用传统引用计数法无法解决循环引用垃圾而是通过GC Roots可达性分析判定对象是否存活从GC Roots根对象出发遍历引用链能遍历到的对象为存活对象无法遍历到的为垃圾对象等待GC回收。常见GC Roots对象虚拟机栈中局部变量引用的对象方法区静态变量、常量引用的对象本地方法栈JNI引用的对象活跃线程、锁对象等1.3 GC核心术语铺垫STWStop-The-WorldGC执行时暂停所有用户业务线程仅保留GC线程工作是GC卡顿的核心原因内存碎片GC回收后产生大量不连续小内存块导致大对象无法分配分代回收JVM将堆内存分为新生代、老年代不同区域采用不同GC算法提升回收效率对象晋升新生代存活对象经过多次GC后晋升至老年代二、三大核心GC算法深度详解原理代码优缺点Java所有垃圾回收器CMS、G1、ZGC、Parallel GC底层均基于三大基础算法衍生优化分别是标记清除算法、复制算法、标记整理算法。2.1 标记清除算法Mark-Sweep——最基础GC算法2.1.1 核心执行原理算法分为两个核心阶段全程伴随STW标记阶段从GC Roots遍历所有对象标记所有可达的存活对象清除阶段遍历整个堆内存回收所有未被标记的垃圾对象释放对应内存核心逻辑只标记存活、只清理垃圾不移动任何对象位置。2.1.2 算法执行流程图解初始内存内存中存在存活对象A、B垃圾对象C、D、E标记后A、B标记为存活C、D、E无标记清除后C、D、E内存释放产生大量不连续空闲内存碎片2.1.3 Java代码模拟标记清除算法通过自定义内存块、对象引用、标记逻辑完整模拟标记清除执行流程/** * 标记清除算法 代码模拟 * 核心流程标记存活对象 - 清除未标记垃圾对象 */publicclassMarkSweepGC{// 模拟堆内存最大容量privatestaticfinalintMAX_MEMORY100;// 模拟内存中的对象数组privatestaticGCObject[]heapMemorynewGCObject[MAX_MEMORY];// 自定义内存对象staticclassGCObject{// 对象是否被标记true存活false垃圾booleanisMarked;// 模拟对象引用GCObjectreference;// 对象占用内存大小intsize;publicGCObject(intsize){this.sizesize;this.isMarkedfalse;}}// 1. 标记阶段从GC Roots标记所有存活对象publicstaticvoidmarkPhase(GCObjectroot){// 递归标记可达对象if(root!null!root.isMarked){root.isMarkedtrue;// 标记当前对象引用的下级对象markPhase(root.reference);}}// 2. 清除阶段回收所有未标记的垃圾对象publicstaticintsweepPhase(){intfreeMemory0;for(inti0;iheapMemory.length;i){GCObjectobjheapMemory[i];// 未标记的对象为垃圾回收内存if(obj!null!obj.isMarked){freeMemoryobj.size;heapMemory[i]null;// 清空对象释放内存}}System.out.println(【标记清除】本次回收空闲内存freeMemory);returnfreeMemory;}// 执行完整标记清除GCpublicstaticvoidmarkSweepGC(GCObjectgcRoot){// STW开始System.out.println(开始执行标记清除GCSTW停顿中...);// 阶段1标记存活对象markPhase(gcRoot);// 阶段2清除垃圾对象sweepPhase();// STW结束System.out.println(标记清除GC执行完毕内存存在碎片\n);}publicstaticvoidmain(String[]args){// 模拟创建存活对象GC Roots可达GCObjectliveObj1newGCObject(20);GCObjectliveObj2newGCObject(15);liveObj1.referenceliveObj2;// 模拟创建垃圾对象无GC Roots引用GCObjectgarbage1newGCObject(10);GCObjectgarbage2newGCObject(25);// 存入堆内存heapMemory[0]liveObj1;heapMemory[1]liveObj1.reference;heapMemory[2]garbage1;heapMemory[3]garbage2;// 执行GC以liveObj1作为GC RootsmarkSweepGC(liveObj1);}}2.1.4 算法优缺点深度分析优点算法逻辑简单、实现难度低无需移动对象、无需修改引用地址执行成本低不占用额外内存空间无内存冗余缺点核心痛点产生大量内存碎片回收后空闲内存不连续大对象无法分配容易触发Full GC两次遍历堆内存标记、清除各遍历一次堆越大效率越低STW时间不稳定碎片化越严重后续GC效率越差2.1.5 适用场景与问题解法适用场景老年代瞬时GC、存活对象多、垃圾对象少的场景早期CMS回收老年代核心算法常见问题最优解法问题1内存碎片过多大对象分配失败OOM解法配合标记整理算法使用、开启JVM碎片整理参数、定期Full GC整理内存问题2大堆内存GC遍历效率低解法采用分代回收缩小单次GC遍历内存范围2.2 复制算法Copying——新生代专属高效算法2.2.1 核心执行原理针对标记清除碎片问题优化核心思想空间换时间无内存碎片。将可用堆内存平均划分为两块大小相等的内存区域同一时间只使用其中一块From区另一块To区空闲备用。GC执行流程标记From区所有存活对象将存活对象完整复制到To区严格有序排列清空From区所有内存互换From/To区域身份2.2.2 适配场景原理Java新生代对象朝生夕灭90%以上对象创建后快速死亡每次GC仅需复制少量存活对象效率极高完美适配新生代Minor GC。2.2.3 Java代码模拟复制算法/** * 复制算法 代码模拟适配新生代Minor GC * 核心流程划分对等内存区 - 复制存活对象 - 清空原内存 - 互换区域 */publicclassCopyingGC{// 单个内存区域容量privatestaticfinalintAREA_SIZE50;// From区当前使用的内存区privatestaticGCObject[]fromAreanewGCObject[AREA_SIZE];// To区空闲备用内存区privatestaticGCObject[]toAreanewGCObject[AREA_SIZE];// 复用自定义内存对象staticclassGCObject{booleanisMarked;GCObjectreference;intsize;publicGCObject(intsize){this.sizesize;this.isMarkedfalse;}}// 标记存活对象publicstaticvoidmarkLiveObject(GCObjectobj){if(obj!null!obj.isMarked){obj.isMarkedtrue;markLiveObject(obj.reference);}}// 核心复制存活对象到To区publicstaticvoidcopyLiveObject(){inttoIndex0;// 遍历From区复制标记的存活对象for(GCObjectobj:fromArea){if(obj!nullobj.isMarked){toArea[toIndex]obj;System.out.println(复制存活对象占用内存obj.size);}}}// 清空From区互换内存区域publicstaticvoidswapAndClear(){// 清空原From区fromAreanewGCObject[AREA_SIZE];// 互换区域原To区变为新From区原From区变为新To区GCObject[]tempfromArea;fromAreatoArea;toAreatemp;System.out.println(内存区域互换完成无内存碎片);}// 执行复制GCpublicstaticvoidcopyingGC(GCObjectroot){System.out.println(开始执行复制GCSTW停顿中...);// 1. 标记存活对象markLiveObject(root);// 2. 复制存活对象到备用区copyLiveObject();// 3. 清空原内存互换区域swapAndClear();System.out.println(复制GC执行完毕\n);}publicstaticvoidmain(String[]args){// 初始化From区2个存活对象多个垃圾对象GCObjectlive1newGCObject(10);GCObjectlive2newGCObject(15);live1.referencelive2;fromArea[0]live1;fromArea[1]live1.reference;fromArea[2]newGCObject(8);// 垃圾对象fromArea[3]newGCObject(12);// 垃圾对象// 执行复制GCcopyingGC(live1);}}2.2.4 新生代优化Survivor双区机制JVM并未直接使用1:1对等分区而是优化为Eden:From:To 8:1:1的内存布局解决1:1分区内存浪费问题Eden区新生代主要内存区域存放新建对象两个Survivor区From/To对等备用区保证复制算法执行仅浪费10%内存内存利用率大幅提升2.2.5 算法优缺点与问题解法优点无任何内存碎片内存空间连续完美支持大对象分配仅复制存活对象垃圾对象直接清空回收效率极高STW时间短适合高频次的新生代Minor GC缺点内存利用率低1:1分区浪费50%内存优化后仍浪费10%存活对象多时代价极高对象存活率高时复制成本指数级上升不适合老年代大对象、长生命周期对象回收常见问题最优解法问题1大对象频繁复制导致GC卡顿解法大对象直接进入老年代规避新生代复制开销调整-XX:PretenureSizeThreshold参数问题2对象过早晋升老年代导致老年代膨胀解法调整晋升阈值-XX:MaxTenuringThreshold延长新生代存活时间2.3 标记整理算法Mark-Compact——老年代终极算法2.3.1 核心执行原理结合标记清除、复制算法双重优势解决碎片问题内存浪费问题是老年代主流GC算法。执行分为两个阶段标记阶段和标记清除一致从GC Roots标记所有存活对象整理阶段不复制、不直接清除而是将所有存活对象向内存一端紧凑移动所有存活对象连续排列最后一次性清空末端所有垃圾内存核心逻辑标记存活、紧凑整理、批量回收。2.3.2 算法执行流程初始内存存活对象分散、夹杂大量垃圾对象、内存碎片严重标记后筛选出所有存活对象整理后存活对象全部紧凑至内存前端后端为整块连续空闲内存无任何碎片2.3.3 Java代码模拟标记整理算法/** * 标记整理算法 代码模拟老年代专属 * 核心流程标记存活对象 - 紧凑整理内存 - 批量回收末端垃圾 */publicclassMarkCompactGC{// 老年代堆内存容量privatestaticfinalintOLD_MEMORY_SIZE100;privatestaticGCObject[]oldMemorynewGCObject[OLD_MEMORY_SIZE];staticclassGCObject{booleanisMarked;intsize;// 记录对象原始内存地址intaddress;publicGCObject(intsize,intaddress){this.sizesize;this.addressaddress;this.isMarkedfalse;}}// 1. 标记存活对象publicstaticvoidmarkPhase(GCObjectobj){if(obj!null!obj.isMarked){obj.isMarkedtrue;}}// 2. 核心整理内存紧凑存活对象publicstaticvoidcompactPhase(){intnewAddress0;// 遍历内存将存活对象紧凑前移for(inti0;ioldMemory.length;i){GCObjectobjoldMemory[i];if(obj!nullobj.isMarked){// 移动存活对象到新地址oldMemory[newAddress]obj;System.out.println(存活对象整理原地址obj.address - 新地址newAddress);}}// 3. 批量清空末端垃圾内存for(intinewAddress;ioldMemory.length;i){oldMemory[i]null;}System.out.println(内存整理完成空闲内存连续无碎片总空闲容量(OLD_MEMORY_SIZE-newAddress));}// 执行标记整理GCpublicstaticvoidmarkCompactGC(GCObjectroot){System.out.println(开始执行标记整理GCSTW停顿中...);// 标记阶段markPhase(root);// 整理回收阶段compactPhase();System.out.println(标记整理GC执行完毕\n);}publicstaticvoidmain(String[]args){// 模拟老年代分散的存活对象和垃圾对象oldMemory[0]newGCObject(15,0);// 存活oldMemory[2]newGCObject(10,2);// 垃圾oldMemory[3]newGCObject(20,3);// 存活oldMemory[5]newGCObject(8,5);// 垃圾// 执行GCmarkCompactGC(oldMemory[0]);}}2.3.4 算法优缺点深度解析优点无内存碎片整理后内存完全连续彻底解决大对象分配失败问题内存利用率100%无需分区冗余无内存浪费适配老年代老年代对象存活率高、生命周期长移动频率低缺点核心痛点STW时间最长需要移动大量存活对象、更新所有引用地址开销极大执行效率低于复制、标记清除算法不适合高频GC场景堆内存越大整理耗时越久2.3.5 适用场景与优化解法适用场景老年代Full GC、对象存活率高、对内存碎片敏感、低频GC场景G1、ZGC老年代回收核心算法常见问题最优解法问题1标记整理STW过长业务卡顿解法采用并发标记整理、分块整理使用G1/ZGC低延迟垃圾回收器问题2频繁Full GC导致服务雪崩解法优化内存参数、避免大对象频繁创建、防止内存泄漏、控制对象晋升频率三、三大GC算法全方位对比面试必背对比维度标记清除算法复制算法标记整理算法核心特点标记存活、清理垃圾、不移动对象分区复制存活对象、清空原内存标记存活、紧凑整理、批量回收内存碎片严重碎片无碎片无碎片内存利用率100%低优化后90%100%STW停顿时间中等短高频高效长低频低效存活率适配高低存活率均可仅适配低存活率仅适配高存活率适用区域老年代临时回收新生代Minor GC老年代Full GC执行开销中等低存活少/高存活多极高四、JVM分代GC算法组合落地生产环境核心4.1 分代算法组合逻辑JVM没有单一使用某一种算法而是分代适配、组合使用最大化GC效率新生代Minor GC核心使用复制算法原因对象朝生夕灭、存活率低、需要高频快速回收、追求低STW老年代Full GC核心使用标记清除标记整理组合算法原因对象存活率高、生命周期长、低频GC、优先保证内存无碎片4.2 主流垃圾回收器底层算法对应关系Serial GC新生代复制算法、老年代标记整理Parallel GC新生代复制算法、老年代标记整理并行优化CMS GC老年代标记清除为主碎片过多时触发标记整理G1 GC分区复制标记整理混合算法ZGC/Shenandoah并发标记移动整理超低延迟优化五、生产环境GC问题实战解法高频故障5.1 问题1新生代GC频繁、CPU飙升根因新生代内存过小、短生命周期对象创建过多复制算法频繁执行解决方案调大新生代内存-Xmn 调整新生代容量优化代码减少临时对象、字符串、集合频繁创建调整Survivor比例减少对象过早晋升5.2 问题2老年代内存碎片、大对象OOM根因CMS标记清除算法产生大量内存碎片连续内存不足解决方案开启CMS碎片整理-XX:UseCMSCompactAtFullCollection设置整理频率-XX:CMSFullGCsBeforeCompaction3替换G1/ZGC回收器从底层规避碎片问题5.3 问题3Full GC卡顿严重、业务超时根因老年代标记整理算法STW时间过长大量对象移动、引用更新解决方案升级低延迟回收器G1、ZGC、Shenandoah避免大对象直接创建优化对象生命周期排查内存泄漏杜绝老年代内存持续膨胀六、高频面试总结必考问答为什么新生代用复制算法老年代不用新生代存活率低、高频GC复制算法效率高、无碎片老年代存活率高复制成本极高适合标记整理标记清除和标记整理的核心区别标记清除只清不挪有碎片、STW短标记整理先挪后清无碎片、STW长复制算法为什么要分区保证存活对象有序复制清空原内存彻底消除内存碎片GC算法核心演进逻辑标记清除简单有碎片→ 复制算法无碎片耗内存→ 标记整理无碎片高稳定七、总结三大GC算法是Java垃圾回收的底层基石没有绝对最优的算法只有场景适配的算法追求高频快速、低延迟→ 新生代复制算法追求简单高效、中等开销→ 标记清除算法追求内存规整、无碎片、高利用率→ 老年代标记整理算法生产环境GC调优的核心就是根据业务场景匹配算法、规避算法缺陷、优化参数阈值从底层解决GC卡顿、OOM、内存碎片等核心问题。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门