浅谈 GC

GC 即垃圾回收机制,回收的是 new 出来的对象,所以在聊 GC 前先看看对象的组成。

对象的组成部分

对象在内存中存储可以分为 3 个区域:对象头、实例数据、对齐填充。下面图中就是一个普通对象实例的数据结构

对象头

HotSpot 虚拟机的对象头包括两部分信息:

  1. Mark Word
    第一部分 mark word 用于存储对象自身的运行时数据,如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程持有锁、偏向线程ID、偏向时间戳等,长度为 32bit64bit
  2. Klass Pointer
    另一部分是 klass 类型指针,即对象指向它的类元数据(在方法区中)的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

实例数据

实例数据部分是对象真正存储的有效信息,也是在代码中所定义的各种类型的字段内容

对齐填充

占位符作用,由于 HotSpot VM 的自动内存管理系统要求对象起始位置必须是 8 字节的整数倍,即对象的大小必须是 8 字节的整数倍。而对象头正好是 8 字节的倍数,因此,当实例数据部分不是 8 字节的整数倍时,就需要通过对齐填充来补全

GC(垃圾回收)

一个程序只要在运行中,那么就会不停的 new 对象,总有一个时间点 Eden 区域会放满,一旦 Eden 区满了之后,虚拟机就会执行 GC,此时的 GCminor GC
那么哪些对象是会被回收的垃圾对象呢?那就涉及到可达性分析和 GC Roots 根对象了,这里不详细展开,简单说一下哪些对象属于** GC Roots** 根对象:

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

下面简单说说回收的过程

新对象分配在 Eden

Eden 区放满后,执行 minor GC,存活的对象会被移到 from 区。上图中对象存活下来,对象2被回收了

在对象头的组成部分 Mark Word 里存储 GC 分代年龄,一个对象每经历一次 GC,那么它的年龄就 +1,如上图所示

当又有新对象放满 Eden 区时,就会再次执行 minor GC,但是这一次会带着 from/to(只有一块区域存放对象,参考复制-回收算法)区一起 GC,然后将 Eden 区和 from/to 区存活的对象都移到 to/from 区,并且对象头中的分代年龄都 +1

Eden 区又又一次被放满后,继续执行上述 GC 过程。
如果一个对象的分代年龄达到 15(默认),就会被移到老年代,那会不会没达到限定年龄就直接进入老年代呢?当然会了,当 from/to 区的空间不够时,就直接存放到老年代,这里简单举例了两种情况,还有其它将对象存入老年代的规则。
最后,随着程序的不断运行,老年代也会被对象占满,这时候发生的 GC 就是 Full GC 了。

posted @ 2021-08-05 13:06  超级鲨鱼辣椒  阅读(138)  评论(0编辑  收藏  举报