JVM - 垃圾回收

1. 对象已死吗?

  • 引用计数算法:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时就减1。无法解决对象之间循环引用的问题。

  • 可达性分析算法:通过一系列的“GC Roots”的对象作为起始点,从这些起始点向下搜索,走过的路径称为引用链,当一个对象到GC Roots没有任何引用链时,则证明此对象是不可用的。可作为GC Roots的对象包括以下几种:

    • 虚拟机栈(栈帧中的本地变量表)中引用的对象;本地方法栈中JNI引用的对象
    • 方法区中类静态属性、常量引用的对象

2. 两次标记

即使在可达性分析中不可达的对象,也并非是非死不可的,要真正宣布一个对象死亡,还需要经历两次标记过程。

第一次标记:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那么它将会被第一次标记并且进行第一次筛选(当对象没有覆盖finalize方法或finalize方法已经被虚拟机执行过,即此对象没有必要执行finalize方法。当对象有必要执行finalize方法时将加入到F-Queue方法中)

第二次标记:对F-Queue中的对象进行第二次标记,对象如果拯救了自己,那么此次标记将其移除“即将回收”的集合;如果对象这时候没有逃脱,那么它就要被回收了。

3. 从GC角度看Java堆

新生代( Eden 区 、 From Survivor 区 和To Survivor 区 )和老年代。
heap

3.1 新生代

是用来存放新生的对象。由于频繁创建对象,所以新生代会频繁触发MinorGC - 新生代GC进行垃圾回收。新生代又分为 Eden区、ServivorFrom、ServivorTo三个区。 各区占比可用-XX:SurvivorRatio参数配置。

  • Eden区:Java新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代,可用-XX:PretenureSizeThreshold参数进行配置)。当Eden区没有足够空间进行分配时就会触发MinorGC,对新生代区进行一次垃圾回收。
  • ServivorFrom :上一次GC的幸存者,作为这一次GC 的被扫描者。
  • ServivorTo: 保留了一次MinorGC过程中的幸存者。
MinorGC过程:MinorGC采用复制算法。

新生代中每次垃圾收集时都会有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。

  1. eden 、 servicorFrom 复制到 ServicorTo ,年龄 + 1
    首先,把Eden和ServivorFrom区域中存活的对象复制到ServicorTo区域(如果有对象的年 龄以及达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1(如果 ServicorTo 空间已满就放到老年区);
  2. 清空Eden和ServicorFrom中的对象;
  3. ServicorTo和ServicorFrom互换,原ServicorTo成为下一次GC时的ServicorFrom 区。

3.2 老年代

主要存放应用程序中生命周期长的内存对象。老年代的对象比较稳定,所以 MajorGC 不会频繁执行。

长期存活的对象进入老年代,何为老年代:

虚拟机给每个对象定义了一个年龄计数器,经过一次MinorGC后仍然存活,则+1,到了晋升老年代年龄阈值,就会晋升到老年代中。可以通过-XX:MaxTenuringThreshold设置。

MajorGC 采用标记清除算法:

对象存活率高、没有额外空间对它进行分配担保,就需要使用标记清除算法进行回收。

首先扫描一次所有老年代,标记出存活的对象,然后回收没有标记的对象。MajorGC的耗时比较长,因为要扫描再回收。MajorGC 会产生内存碎片,为了减少内存损耗,我们一般需要进行合并或者标记出来方便下次直接分配。当老年代也满了装不下的 时候,就会抛出OOM(Out of Memory)异常。

3.3 永久代

PermGen(永久代),其实指的就是方法区。由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。

“PermGen space”其实指的就是方法区。不过方法区和“PermGen space”又有着本质的区别。前者是 JVM 的规范,而后者则是 JVM 规范的一种实现

永久代主要存放 Class 和 Meta(元数据)的信息,Class 在被加载的时候被放入永久区域,它和和存放实例的区域不同,GC 不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的Class的增多而占满,终抛出OOM异常。

JDK 1.8中, HotSpot 已经没有 “PermGen space”这个区间了,取而代之是Metaspace(元空间) 。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。参考传送门

4. GC分类

  • Full GC:针对整个新生代、老年代、元空间(metaspace,java8以上版本取代perm gen,即永久代)的全局范围的GC

    • 触发条件: 当准备要触发一次young GC时,如果发现young GC的平均晋升大小比目前old gen剩余的空间大,则不会触发young GC而是转为触发full GC!
  • Young GC(Minor GC):当young gen中的eden区分配满的时候触发。注意young GC中有部分存活对象会晋升到old gen,所以young GC后old gen的占用量通常会有所升高。

    • 触发条件: eden区空间满了
  • Major GC:清理永久代,许多 Major GC 是由 Minor GC 触发的

此处请参考逼乎:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值