JVM笔记

  1. 类加载机制
    1. 类的生命周期
  2. JVM 内存结构
  3. 双亲委派机制
  4. JVM 虚拟机栈
    1. 晋升到老年代
  5. 垃圾判断算法
  6. 垃圾回收算法
  7. GC 过程
  8. 垃圾回收器

image-20240312160432882

类加载机制

类的生命周期

加载、验证、准备、解析、初始化

准备阶段:为类的 static 变量在方法区分配内存,将其初始值置为 0。被 final 修饰的常量会直接赋值。

JVM 内存结构

  • 线程私有:Java虚拟栈、程序计数器、本地方法栈
  • 线程共享:方法区、堆内存

双亲委派机制

Java 在尝试加载一个类时,系统首先判断这个类是否被加载过,已经加载的类直接返回,否则才会尝试加载。类加载器会将加载任务先委托给它的父加载器去尝试加载这个类,一直到达顶层的类(Bootstrap)只有在父加载器无法加载该类时(找不到对应的类),子加载器才会尝试去加载。

JVM 虚拟机栈

每个Java虚拟机线程都有一个私有的Java栈,与线程同时创建。Java栈中保存着帧信息,每个方法在执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。

局部变量表、操作数栈、动态链接、方法返回地址。

image-20240312192522896

GC 垃圾回收,主要是在伊甸园区和养老区

  • 新生代:诞生、成长、死亡的地方。分为伊甸园区、From、To 幸存区(0,1)。

  • 老年代

晋升到老年代

  • 在程序运行过程中,新生代GC会反复发生,长寿对象会在S0和S1之间反复交换,年龄也会越来越大,当对象达到年龄上限时,会被晋升到老年代。这个年龄上限默认是15。
  • 大对象会跨过年轻代直接分配到老年代。
  • 某个年龄和以下年龄的对象总大小大于幸存区的一半,年龄大于或等于该年龄的对象可以进入老年代。
  • 老年代空间担保原则:在做任何一次 Minor GC 时,老年代需要确保自己的内存大于新生代所有对象的总和。如果设置了HandlePromotionFailure参数,还会进一步判断是否大于之前 Minor GC 进入老年代对象的平均大小。没有的话就直接 Full GC。

现在可以尝试 Minor GC 了,如果 Minor GC 后,存活的对象小于幸存区大小,就进入幸存区。如果大于幸存区,但小于老年代空间,就进入老年代。如果既大于幸存区又大于老年区,触发 Full GC。

在 jdk8 后,永久代改了个名字(元空间):这个区域在本地内存,存储的是 java 运行时的一些环境或类信息。这个区域不存在垃圾回收。方法区在元空间

非堆内存:方法区、元空间

  • JDK 1.8 之后,无永久代,替代为元空间,不存在于 JVM,使用的是本地内存。

image-20240312200859515

垃圾判断算法

  • 引用计数算法:两个对象循环依赖导致无法回收。
  • 可达性分析算法:通过GC Roots 开始找,与它相连接的就是可达对象。
  • 三色标记算法

初始标记:寻找所有被 GCRoots 直接引用的对象。这里需要 Stop the World。

并发标记:对初始标记中标记的对象进行整个引用链的扫描,这里可以与用户线程同步。

重新标记:并发标记会耗费较长时间,这段时间中对象的引用可能会改变,用来处理这些问题。该过程需要 Stop the World。

并发清除:将标记为垃圾的对象进行清除,不需要 Stop the World。

垃圾回收算法

  • 标记-清除:将存活的对象进行标记,然后清除未标记的对象。(会产生内存碎片)image-20240407112632893

  • 标记-整理:让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。image-20240407112759472

  • 复制算法:将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存满了就将存活对象复制到另一块,再把使用过的内存空间一次性清理。image-20240407113408523

  • 分代收集:将内存划分为几块,如堆分为新生代和老年代。

新生代一般使用复制算法进行垃圾回收。复制算法将新生代分为 Eden区和两个幸存区(From 区、To 区)。当 Eden 区满时,触发 Minor GC,将存活对象移动到一个幸存区,然后清空 Eden 区。这个过程循环反复,直到一个幸存区满了,再触发 Minor GC,将 Eden 区和 From 区的存活对象移到另一个幸存区,清空这个幸存区。

老年代一般采用标记-清除和标记-整理算法。

GC 过程

  1. 新创建的对象大多分配在 Eden 区,当Eden区满了发生 Minor GC。
  2. GC活下来的对象放到幸存区的S0区,S0区满了触发 Minor GC,S0区存活的对象会放入S1区。
  3. S1满了之后GC,存活的对象放到S0区,这样反复每GC一次,对象的年龄就增加一,到达某个值后,就晋升到老年代。

垃圾回收器

image-20240422210101635

Serial:单线程回收。新生代用复制算法,老年代用标记-整理算法。

Parallel Scavenge、Parallel Old:新生代用复制算法,老年代用标记-整理算法。

以上两种方式都会导致用户线程暂停,进行垃圾回收。

分代收集器:CMS 使用三色标记算法

分区收集器:G1、ZGC


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1216271933@qq.com

×

喜欢就点赞,疼爱就打赏