JVM——垃圾回收

发布于:2025-07-01 ⋅ 阅读:(18) ⋅ 点赞:(0)

在Java开发中,JVM不仅负责运行Java字节码,还通过自动内存管理机制帮助开发者避免手动内存管理的复杂性。

1. JVM内存模型

JVM的内存模型主要包括以下几个部分:

  • 方法区(JDK8之后叫元空间): 存储类信息,常量池,静态变量
  • 堆:所有线程共享的一块内存区域,存放对象实例
  • 栈:线程私有
  • 程序计数器:线程私有,记录当前线程执行的字节码行号
  • 本地方法栈:为Native方法服务

2. Java堆的划分

  • 年轻代
    • Survivor 区0
    • Survivor 区1
    • Eden Space伊甸园区
  • 老年代

其中:年轻代的GC成为Young GC,老年代的GC叫做Full GC

3. 什么是垃圾

在JVM中,“垃圾”指的是那些不再被使用的对象。具体来说,如果一个对象不能通过程序中的任何引用链从GC Roots到达,那么这个对象就被认为是垃圾。

GC Roots

GC Roots是一组必须活跃的引用,它们作为可达性分析的起点。以下是一些常见的GC Roots的例子:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象:比如正在执行的方法中的局部变量。
  • 方法区中类静态属性引用的对象:例如类级别的静态成员变量。
  • 方法区中常量引用的对象:如字符串常量池里的引用。
  • 本地方法栈中JNI(即一般说的Native方法)引用的对象

如何判断对象是否为垃圾

有两种主要的方法用来确定哪些对象被认为是垃圾:

  1. 引用计数法(Reference Counting)

    • 这种方法给每个对象关联一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值减1。任何时刻计数器为0的对象就是不可能再被使用的。
    • 但是这种方法很难解决对象之间的循环引用问题,因此在Java中并没有采用这种方法。
  2. 可达性分析(Reachability Analysis)

    • JVM使用这种方法来判断对象是否存活,它通过一系列称为“GC Roots”的对象作为起始点,开始向下搜索,搜索走过的路径称为引用链(Reference Chain),当一个对象没有任何引用链与GC Roots相连时,则证明此对象是不可用的。
    • 这是目前主流的垃圾判定算法,在Java中得到了广泛应用。

4. 如何进行垃圾回收

4.1 垃圾回收算法

标记-清理法:如果堆中的对象没有被GCRoots指向,我们就判断这些对象为垃圾,并标记起来,然后再扫描一遍,将标记的对象清理掉。但是缺点是会产生内存碎片。主要用于FullGC

标记-整理算法:清理垃圾的时候,让存活的对象填充内存碎片,但是代价是开销太大。主要用于FullGC

复制算法:将堆的区间分为1区和2区,缺点是2倍内存主要用于YoungGC

4.2 GC触发条件

4.2.1 YoungGC

YoungGC:当我们new对象实例时,对象会出生在伊甸园区,伊甸园区快满了的时候,会触发youngGC,通过复制算法。注意:S0区和S1区交替工作。

S0:S1:Eden的内存分配大小默认是1:1:8。这是因为大部分对象都是“朝生夕死”的。

(1)判断Eden区和S1区存活对象

(2)将Eden区和S1区存活的对象,复制到S0区,并清空S1区和Eden区

(3)循环1,2的过程

  • E+S1的存活对象复制到S0,清空E+S1
  • E+S0的存活对象复制到S1,清空E+S0
  • 循环....

注意:每次GC,对象的age都会+1,当对象的年纪到达6/15岁,这个对象会被移除到Old区。

4.2.2 FullGC

当Old区间快满了,会引起OldGC,但是OldGC往往伴随着YoungGC,所以也叫FullGC。整个Java程序暂停,进行垃圾回收。采用标记清理/标记整理算法

4.3 垃圾收集器

年轻代垃圾回收器:ParNew(内部采用复制算法实现)

老年代垃圾回收器:CMS(标记清理算法实现)

最新版JDK:G1垃圾收集器。


网站公告

今日签到

点亮在社区的每一天
去签到