常见知识整理-垃圾回收机制

对象被判断为垃圾的标准

引用计数法

目前主流的垃圾收集器实现都没有采用这种算法

  1. 每个对象实例都有一个引用计数器,被引用则+1,取消引用则-1。
  2. 通过判断对应的引用数量来决定是否可以被回收
  3. 任何引用计数为0的对象实例都可以被当作垃圾回收
    优点: 执行效率高,程序执行受影响较小
    缺点: 无法检测出循环引用的情况,导致内存泄漏

可达性分析

通过判断GC Root对象的引用链是否可达来决定对象是否可以被回收

可以作为GC Root的对象

  1. 虚拟机栈中引用的对象(栈帧中的本地变量表)
  2. 方法区中常量引用的对象
  3. 方法区中类的静态属性引用的对象
  4. 本地方法栈中JNI(native方法)的引用对象

垃圾回收算法

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

标记待回收对象,然后清除,会有内存碎片化问题

复制算法

解决碎片问题,顺序分配内存,简单高效,适用于对象存活率低的场景(新生代
缺点:浪费内存一小段的内存

标记-整理算法

标记: 对存活的对象标记
整理: 移动所有存活的对象,且按照内存地址依次排序,然后将末端内存地址以后的内存全部回收。
避免内存的不连续性,不用设置两块内存互换,使用于存活率高的场景。(老年代

分代收集算法

新生代使用复制算法,老年代使用标记-整理算法
在这里插入图片描述
Minor GC 是新生代垃圾收集
Full GC 是老年代垃圾收集,一般会伴随Minor GC

年轻代:尽可能快速的收集生命周期短的对象
在这里插入图片描述

对象如何晋升到老年代

  1. 默认经历15次Minor GC依然存活的对象
  2. Survivor区中存在放不下的对象
  3. 大对象直接进入老年代(-XX:+PretenuerSizeThreshold),默认全部先放年轻代。

触发Full GC的条件

  1. 老年代空间不足
  2. CMS GC时出现promotion failed,concurrent mode failure
  3. Minor GC晋升到老年代的平均大小大于老年代的剩余空间
  4. 当MinorGC后剩余的对象占用空间,大于Survivor to空间的50%(根据配-XX:TargetSurvivorRatio=50), 也会将年龄最大的(即使没有对象年龄没达到15)那部分对象移入老年代;
    例如: 年轻代空间为1G,其Survivor空间为100M.
    年龄为3的对象: 10M
    年龄为2的对象: 20M
    年龄为1的对象: 10M
    Eden区存活对象: 11M
    此时进行MinorGC, 所有存活对象共51M,大于Survivor空间的一半,则年龄为3的10M对象会被移入老年代.
  5. 当Survivor空间中相同年龄所有对象的大小总合大于Survivor空间的50%(根据配-XX:TargetSurvivorRatio=50), 则年龄大于等于这个年龄的对象也会直接进入老年代;
  6. 显示调用System.gc()
  7. 使用RMI来进行RPC或者管理的JDK应用,每小时执行1次Full GC

Stop-the-World

JVM由于要执行GC而停止了应用程序的执行,除了GC线程,其它应用程序线程全部等待状态。多数GC优化通过减少Stop-the-World发生的时间来提高程序性能。

Safepoint

可达性分析中过程中,对象引用关系不会发生变化的点
垃圾收集时,应用程序不是在随便哪个点都停顿下,而是到达安全点才会停顿。
产生Safepoint的地方:方法调用循环跳转异常跳转等位置
GC过程中如果有线程不在安全点,会等到所有的线程都执行到安全点再执行GC。

常用的调优参数

-XX:SurvivorRatio Eden和Survivor的比值,默认8:1:1
-XX:NewRatio 老年代和年轻代内存大小的比例
-XX:MaxTenuringThreshold 对象从年轻代晋升到老年代经历的GC次数最大阈值

垃圾收集器

年轻代收集器

Serial收集器(-XX:+UseSerialGC,复制算法)
  1. 单线程收集,进行垃圾收集时,必须暂停所有工作线程
  2. 简单高效,JDK Client模式下默认的年轻代收集器
ParNew 收集器(-XX:+UseParNewGC,复制算法)
  1. 多线程收集,其余的行为特点和Serial收集器一样
  2. 在多核下执行才有优势,单核执行效率不如Serial
  3. 默认开启的线程数和CPU数量相同,可以通过参数控制线程数
  4. 在Server模式下是非常重要的收集器,除Serial外,目前唯一可以和CMS配置使用的收集器
Parallel Scavenge收集器(-XX:+UseParallelGC,复制算法)

吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)
更短暂的停顿时间,可以快速响应用户请求,给用户良好的体验。而高吞吐量可以高效率利用CPU时间,尽可能快的完成运算任务。适合在后台运算,不需要太多交互的情况。

  1. 比起关注用户线程停顿时间,该收集器更加关注系统的吞吐量。
  2. 在多核执行下才有优势,Server模式下默认的年轻代收集器
  3. 可以通过参数-XX:+UseAdaptiveSizePolicy由虚拟机自动调节内存设置

-XX:ParallelGCThreads=数字N 表示启动多少个GC线程
-XX:+UseParallelGC = 新生代ParallelScavenge + 老年代ParallelOld
-XX:-UseParallelOldGC = 新生代ParallelScavenge + 老年代SerialOld

老年代收集器

Serial Old收集(-XX:+UseSerialOldGC,标记-整理算法)
  1. 单线程收集,收集时需要暂停所有工作线程
  2. 简单高效,Client模式下默认的老年代收集器
Parallel Old收集器(-XX:+UseParallelOldGC,标记-整理算法)
  1. 多线程,吞吐量优先
CMS收集器(-XX:+UseConcMarkSweepGC,标记-清除算法)
  1. 几乎能与用户线程同时工作

  2. 尽可能缩短用户线程停顿时间

  3. 如果有较多相对存活较长的对象,更适合使用CMS

    CMS垃圾回收过程

    1. 初始标记 需要stop-the-world,从垃圾回收的根对象开始,扫描能和根对象直接关联的对象并标记。
    2. 并发标记 并发追溯标记,应用程序不需要停顿
    3. 并发预清理 查找执行并发标记阶段从年轻代晋升到老年代的对象
    4. 重新标记 暂停用户线程,扫描CMS堆中的剩余对象
    5. 并发清理 清理垃圾对象,程序不会停顿
    6. 并发重置 重置CMS收集器的数据结构

缺点: 采用的标记-清除,会产生内存碎片。老年代空间会随着应用时长被逐步耗尽,最后将触发担保机制对内存进行压缩,(Serial Old)串行老年代收集器将会以Stop the world方式进行一次GC,从而造成较大停顿时间。
CMS也提供了参数-XX:CMSFullGCsBeForeCompaction来指定执行多少次full GC才会做压缩,默认是0,也就是在默认配置下每次CMS GC顶不住了而要转入full GC的时候都会做压缩

G1收集器(-XX:+UseG1GC, 复制 + 标记-整理算法)

既用于新生代也用于老年代

  1. G1能够充分利用多CPU,多核环境硬件优势,尽量缩短STW时间
  2. G1整体上采用标记-整理算法,局部是通过复制算法(不会产生内存碎片)
  3. 宏观上看G1不再区分新生代和老年代,把内存划分成多个独立的子区域(Region),可以近似理解为一个围棋的棋盘.
  4. G1收集器里面将整个的内存区域都混合在一起,但其本身依然在小范围内进行年轻代和老年代的区分
  5. 整个内存分区不存在物理上的年轻代和老年代的区别,也不需要完全独立的survivor堆做复制准备每个分区都可能随G1的运行在不同代中间切换

各收集器可搭配方式

在这里插入图片描述
有连线表示可以搭配使用

Object的finalize()方法的作用是否与C++的析构函数相同

  1. 与C++的析构函数不同,析构函数调用确定,而finalize()不确定
  2. 将未被引用的对象放置在F-Queue队列
  3. 方法执行随时可能被终止
  4. 给了对象最后依次重生的机会
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值