GC垃圾回收

本文深入探讨Java垃圾回收机制,包括新生代与老年代划分、MinorGC与FullGC过程、不同垃圾回收算法如标记清除、复制算法及分代收集算法的特点与应用。同时解析了如何确定垃圾对象的引用计数法与可达性分析方法。
摘要由CSDN通过智能技术生成

java堆

java堆从GC角度还可以细分为:新生代和老年代

新生代

新生代又可以分为eden区,from区 ,to区
用来存放新生的对象,一般占据堆的1/3空间。由于频繁创建对象,所以新生代会频繁触发MinorGC进行垃圾回收,采用复制算法

  • eden
    java新对象的出生地,所有刚创建的对象都会进入eden区,当Eden区不够的时候回触发MinorGC,对新生代进行一次垃圾回收
  • ServivorFrom
    上一次GC所未清除的对象,以及下次将被GC扫描的对象
  • ServiviorTo

新生代中的MinorGC

MinorGC采用复制算法

过程:

  • eden、ServiviorFrom中的对象复制到ServiviorTo区域,若对象年龄达到老年的标砖,则复制到老年代,同时对象的年龄+1
  • 清空eden和ServiviorFrom区中的全部对象
  • ServiviorTo和ServiviorFrom区进行互换,原ServiviorTo成为下一次GC的ServiviorFrom区

老年代

主要存放应用程序中生命周期长的内存对象,也就是年龄比较大的对象。
老年代对象比较稳定,因此FullGC不会频繁执行。
FullGC触发条件:

  • 当老年代空间不够时触发
  • 无法找到足够大的连续空间分配给新创建的较大对象

注意:如果执行完FullGC仍然无法给该对象分配空间,那么就会抛出异常,异常类型就是OutOfMemoryError。

FullGC

FullGC采用标记清除法

过程:

  • 扫描所有老年代,标记出存活的对象
  • 回收所有未标记的对象

永久代

主要存放类信息和元数据信息,GC不会在主程序运行期对永久区进行清理,所以这也导致了永久代的区域会随着加载的class增多而饱和,最终抛出OOM异常

java8中的元数据区

在java8中,永久代被移除,被称为元数据区(元空间)所取代。
区别:

  • 元数据区并不在虚拟机中,而是使用本地内存。元数据区的大小受本地内存限制

垃圾回收与算法

如何确定垃圾

  • 引用计数法
    在java中引用和对象时关联的,如果想要操作对象则必须引用。因此可以引用计数来判断对象是否回收。如果对象引用计数为0,则可以被回收了。简单的说就是对象每次被引用,计数器+1,当引用失效后计数器-1,当计数器0时,将表示对象不被使用,垃圾回收期将回收该对象使用的内存。
    优点:
    引用计数器执行速度快,程序不会被长时间打断
    缺点:
    无法检测出循环引用。所谓循环引用就是父对象对子对象有一个引用,而子对象又反过来引用父对象,这样,他们的引用计数用不可能为0。
  • 可达性分析
    为了解决引用计数法的循环引用问题,java使用了可达性分析的方法,如果一个对象没有可达路径,则成该对象是不可达的。但是不可达对象不等于可回收对象,GC还会再给两次机会,回收对象经过两次标记过程变为可达对象,则不回收。

垃圾回收算法

  • 标记清除法
    标记需要回收的对象,在清除阶段进行清除
    标记轻蹙算法根据特定的算法(如引用计数法或可达性分析等)标记处内存中哪些对象可以回收。
    缺点:内存碎片化严重,效率低
    在这里插入图片描述
  • 复制算法
    解决内存碎片化提出的算法。
    按内存容量将其划分为等大小的两块,每次只使用其中一块,一块内存满后,将存活的对象复制到另一块上去,并进行压缩,然后清除这块内存。
    问题:内存效果高,不易产生碎片,但是将内存压缩到了原来的一半
  • 标记压缩算法
    标记后,将存活对象一道内存一端,然后清除边界外的对象,这样就解决了碎片化严重的问题
  • 分代收集算法
    核心思想是根据对象存活的不同生命周期将内存划分为不同的域。将堆划分为新生代和老年代。
    对于新生代和老年代来说,新生代回收频率很高,但是每次回收耗时很短,而老年代回收频率较低,但是耗时会相对较长,所以应该尽量减少老年代的GC.
    注意:java中的垃圾回收机制基本上是多种算法的结合,不会单单只是用一种算法

垃圾回收过程

不可达对象并不会马上被回收,而是要经过至少两次标记的过程

  • 第一次标记过的对象,会检查该对象是否重写了finalize()方法。若没有重写该方法,则加入即将回收集合,或重写了则放入另一个F-Query队列。
  • 第二次标记之前,对所有对象逐个执行finalize()方法,这是对象避免自己被清除的最后手段。如果对象在执行finalize()方法时,重新与GC roots引用链相连,则第二次标记时将对象从F-Query队列清除,不会被回收。但是,这种好事不会无限发生,曾经执行过一次finalize()的对象,如果再被标记,那就只能被等待清除了
  • GC将对F-Queue中的对象进行第二次小规模的标记,将队列中重新与GC Roots引用链恢复连接的对象清除出“即将回收”集合。

finalize作用

finalize()方法是在垃圾收集器清除对象之前对这个对象调用的,确定该对象却是没有被引用。它是object类中定义的,因此所有类都继承了它。

垃圾回收时的停顿现象

java进行垃圾回收时,会中断所有应用线程,目的是这样才能使系统不产生新的垃圾,保证系统装填在某一瞬间的一致性,有利于更好的标记垃圾对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值