【Java八股面试系列】JVM-垃圾回收

本文详细介绍了Java中的垃圾回收机制,包括堆空间结构、内存分配原则、分代收集机制、MinorGC流程、空间分配担保、对象存活判定算法(如引用计数法和可达性分析)以及各种垃圾收集器(如Serial、ParNew、ParallelScavenge、CMS和G1)的原理和应用。还讨论了强引用、软引用、弱引用和虚引用等引用类型及其在内存管理中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

垃圾回收

堆空间的基本结构

内存分配和回收原则

分代收集机制

Minor GC 流程

空间分配担保

老年代

大对象直接进入老年代

长期存活的对象将进入老年代

GC的区域

对象存活判定算法

引用计数法

可达性分析算法

finalize()

字符串常量判活

类判活

垃圾回收算法

标记清除算法

标记复制算法

标记整理算法

垃圾收集器

Serial(串行)收集器

ParNew收集器

Parallel Scavenge收集器

Serial Old 收集器

Parallel Old 收集器

CMS 收集器

G1 收集器

其他引用类型

强引用

软引用

弱引用

虚引用

 参考文章


垃圾回收

当需要排查各种内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。

堆空间的基本结构

Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配。同时,Java 自动内存管理最核心的功能是 内存中对象的分配与回收。

Java 堆是垃圾收集器管理的主要区域,因此也被称作 GC 堆(Garbage Collected Heap)

从垃圾回收的角度来说,由于现在收集器基本都采用分代垃圾收集算法,所以 Java 堆被划分为了几个不同的区域,这样我们就可以根据各个区域的特点选择合适的垃圾收集算法。

在 JDK 7 版本及 JDK 7 版本之前,堆内存被通常分为下面三部分:

  1. 新生代内存(Young Generation):新生代主要存储新创建的对象。当对象被创建时,它们首先会被分配到新生代。

  2. 老生代(Old Generation):老年代主要存储长时间存活的对象,老年代的垃圾回收频率相对较低,因此其大小通常比新生代大得多。

  3. 永久代(Permanent Generation):然方法区和永久代都用于存储类的元数据信息,但它们之间有一些区别。方法区主要存储加载到JVM中的类的信息,而永久代则存储类的元数据信息,这些信息是类加载时所需要的。永久代的存在使得Java具有了动态加载类和实现类的反射机制等功能。

他们三个在堆中的占比为8:1:1,JDK 8 版本之后 PermGen(永久) 已被 Metaspace(元空间) 取代,元空间使用的是直接内存

内存分配和回收原则

分代收集机制

不同的分代内存回收机制也存在一些不同之处,在HotSpot虚拟机中,新生代被划分为三块,一块较大的Eden空间和两块较小的Survivor空间,默认比例为8:1:1,老年代的GC频率相对较低,永久代一般存放类信息等(其实就是方法区的实现)如图所示:

image-20240129140723059

那么它是如何运作的呢?

首先,所有新创建的对象,在一开始都会进入到新生代的Eden区(如果是大对象会被直接丢进老年代),在进行新生代区域的垃圾回收时,首先会对所有新生代区域的对象进行扫描,并回收那些不再使用对象:

image-20240129140902070

接着,在一次垃圾回收之后,Eden区域没有被回收的对象,会进入到Survivor区。在一开始From和To都是空的,而GC之后,所有Eden区域存活的对象都会直接被放入到From区,最后From和To会发生一次交换,也就是说目前存放我们对象的From区,变为To区,而To区变为From区:

image-20240129141220032

接着就是下一次垃圾回收了,操作与上面是一样的,不过这时由于我们To区域中已经存在对象了,所以,在Eden区的存活对象复制到From区之后,所有To区域中的对象会进行年龄判定(每经历一轮GC年龄+1,如果对象的年龄大于默认值为15,那么会直接进入到老年代,否则移动到From区)

image-20240129141234946

最后像上面一样交换To区和From区,之后不断重复以上步骤。

垃圾回收的分类可以分为Minor GC,Major GC, Full GC

  • Minor GC - 次要垃圾回收,主要进行新生代区域的垃圾收集。

    • 触发条件:新生代的Eden区容量已满时。

  • Major GC - 主要垃圾回收,主要进行老年代的垃圾收集。

  • Full GC - 完全垃圾回收,对整个Java堆内存和方法区进行垃圾回收。

    • 触发条件1:每次晋升到老年代的对象平均大小大于老年代剩余空间

    • 触发条件2:Minor GC后存活的对象超过了老年代剩余空间

    • 触发条件3:永久代内存不足(JDK8之前)

    • 触发条件4:手动调用System.gc()方法

Minor GC 流程

空间分配担保

Survivor区无法容纳的对象直接送到老年代,让老年代进行分配担保(当然老年代也得装得下才行)在现实生活中,贷款会指定担保人,就是当借款人还不起钱的时候由担保人来还钱。

老年代

大对象直接进入老年代

大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。

大对象直接进入老年代的行为是由虚拟机动态决定的,它与具体使用的垃圾回收器和相关参数有关。大对象直接进入老年代是一种优化策略,旨在避免将大对象放入新生代,从而减少新生代的垃圾回收频率和成本。

  • G1 垃圾回收器会根据 -XX:G1HeapRegionSize 参数设置的堆区域大小和 -XX:G1MixedGCLiveThresholdPercent 参数设置的阈值,来决定哪些对象会直接进入老年代。

  • Parallel Scavenge 垃圾回收器中,默认情况下,并没有一个固定的阈值(XX:ThresholdTolerance是动态调整的)来决定何时直接在老年代分配大对象。而是由虚拟机根

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值