JavaSE知识点总结:JVM和GC篇

JVM虚拟机和GC

文档源于JDK1.8 JVM
注:图片来自网络,有版权问题请联系我删除。

1、虚拟机结构

JavaSE知识点总结:JVM和GC篇
JVM虚拟结构包括:类加载器、执行引器、运行时数据区
运行时数据区:堆、虚拟机栈、本地方法栈、pc寄存器(程序计数器)、方法区(元空间)。

  • 方法区(元空间)主要用于存储运行时常量池、已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的法代码等。1.8后删除了永久代、元空间是分配到直接内存中的。
  • 字符串常量池分配在堆中
  • 堆内存和方法区是线程共享的,虚拟机栈、本地方法栈、程序计数器是线程独有的。

2、堆内存分代模型

  • 堆分为新生代 (1/3)、老年代 (2/3)
  • 新生代 = Eden+From survivor+To survivor (8:1:1)
  • 堆大小 = 新生代+老年代

3、垃圾回收

  • 新生代:MinorGC 也叫(YoungGC),Eden区满时触发,复制算法
  • 根可达算法。Roots 指 虚拟机栈中引用的对象、方法区中类静态属性、常量,本地方法栈中java本地接口引用的对像
    (复制存活对象) from eden+s1 to s2,清空s2,循环。
    Suvivor空间不足,直接进入老年代
  • 老年代:FullGC&MajorGC
    一直未被回收的对象
    老年代满了触发FGC,STW

4、垃圾回收算法

  • 标记清除法–位置不连续、产生碎片
  • 复制算法–没有碎片、浪费空间
  • 标记压缩法–没有碎片、效率偏低

5、CMS和G1比较

CMS(Concurrent Mark-Sweep Collector)

并发标记清除收集器,它是一个多线程并发回收的老年代垃圾收集器,它使用的是标记-清除算法。

  • 特点:停顿时间短,吞吐量大,并发收集
  • 缺点:对cpu要求高、无法收集浮动垃圾、容易产生碎片
  • 过程:初始标记>>并发标记>>重新标记>>并发清理
    初始标记重新标记标记阶段会STW
    hotspotGC回收器优化指南中不推荐CMS,建议使用G1

G1(Garbage First GC)

垃圾优先收集器,是一个面向服务端的JVM垃圾收集器,适用于多核处理器、大内存容量的服务端系统。
它满足短时间停顿的同时达到一个高的吞吐量。从JDK 9开始,G1成为默认的垃圾回收器。

适合场景:

  • Full GC持续时间太长或者太频繁
  • 对象的创建速率和存活率变动很大
  • 应用不希望停顿时间长(长于0.5s甚至1s)

特点:

1、根据堆空间大小分割成了若干个Region,内存区域不连续。并且新生代和老年代的区域可以动态改变。
2、Young GC是多线程并行的,会有短暂的STW,当Eden区的空间占满之后,会触发Young GC,G1将Eden和Survivor中存活的对象拷贝到Survivor,或者直接晋升到Old Region中。
3、Old GC 当堆空间的占用率达到一定阈值后会触发Old GC。默认设置是45%。
OldGC过程:
Initial-Mark阶段和下一个Young GC一起执行,一旦Initial-Mark完成,一个多线程并行的Marking阶段开始去标记老年代所有存活的对象。当并行Marking阶段完成,一个并行的Stop-the-World的阶段开始去标记所有的对象。Remark节点结束后,G1有老年代所有Region的完整的标记信息,如果这时老年代没有任何存活对象,那么下一个阶段Cleanup阶段就不需要额外的GC工作了。

流程描述:
Initial-Mark-> Concurrent Root Region scanning->Concurrent Marking-> Remarking->Cleanup。

  • 在垃圾回收的最开始有一个短暂的时间段(Inital Mark)会停止应用(stop-the-world)
  • 然后应用继续运行,同时G1开始Concurrent Mark
  • 再次停止应用,来一个Final Mark (stop-the-world)
  • 最后根据Garbage First的原则,选择一些内存块进行回收。(stop-the-world)

Region的定义:
Available Region=可用的空闲Region
Eden Region = 年轻代Eden空间
Suivivor Region=年轻代Survivor空间
所有Eden和Survivor的集合=整个年轻代
Old Region=老年代Region
Humongous Region=大对象Region。大对象是指占用大小超过一个Region50%空间的对象

RSet(Remembered Set)

  • 基于老年代的收集器采用Heap里不同区域区分/隔离对象,这些不同的区域里面的对象对应了不同年代。这样年代收集器可以集中精力在最近分配的对象上,因为它们会发现一些对象不久会死亡。这些年代在堆里可以被分别收集,这样不用扫描整个Heap,可以节省时间和减小响应时间,并且存活时间长的对象不用来回复制,减少了拷贝和引用更新开销。
  • 为了方便收集器的独立性,许多GC维持了每个年代的RSet。每一个RSet是一个数据结构,它维护并跟踪收集器单元的内部引用,如G1 GC的Region一样,减少了扫描整个Heap堆获取信息的耗时。当G1 GC执行了一个Stop-the-world收集(年轻代或混合代),它可以通过CSet扫描Region的RSets。一旦存活对象被移除,它们的引用立即被更新。
  • Garbage First 垃圾优先是指优先处理那些垃圾多的内存块的意思

6、JDK8默认GC

UseParallelGC 即 Parallel Scavenge + Serial Old Parallel
Scavenge 年轻代并行回收器,也叫吞量优先收集器。多线程、独占式的收集器;

特点:

  • 高吞吐量。
  • STW时间可设置,牺牲内存空间。
  • 自适应调节内存比例。

Serial 单线程独占式GC,采用标记压缩算法。Full GC会STW

7、JVM类加载过程

  • JVM的类加载机制是指虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型的实现过程。

类加载过程的几个步骤:

  • 加载:查找和导入二进制字节码文件。并在Java堆中创建一个该类或接口的Class对象,作为对方法区中这些数据的访问入口。
  • 链接:将类的二进制代码合并到JRE中。链接过程包括验证、准备、解析三个阶段。
    验证:确保二进制文件结构上的正确性。
    准备:给静态变量分配内存空间并设置默认值。
    解析:将常量池中的符号引用替换为直接引用的过程。
  • 初始化:对类的静态变量、静态代码块执行初始化操作。