基础

基本概念

  • 弱分代假说(weak generational hypothesis):多数对象的生命周期很短。
  • 分代回收(generational collection):基于弱分代假说,将内存空间分为多个区域(代),在每一代填满时执行垃圾回收;不同代使用不同的垃圾回收算法。

内存结构

Java程序内存结构:

  • 堆内存(Heap Space)
    • 新生代(Young Gen)
      • Eden
      • Survivor 0/1
    • 老生代(Old Gen)
  • 栈内存(Stack)
  • 堆外内存(Non-heap Space)

垃圾回收

如何查找垃圾

  • 引用计数:将引用数量为0的对象定义为垃圾;缺点是无法处理循环引用。
  • 可达性分析:从根结点开始遍历并标记,将没有标记的对象定义为垃圾。

回收算法

  • 标记-清除(Mark-Sweep):第一阶段遍历并标记对象,第二阶段将未标记对象对应的内存空间标记为未使用。优点是不存在内存复制,缺点是可能产生内存碎片。
  • 标记-整理(Mark-Compact):与标记-清除相比,第一阶段不变,第二阶段会将存活对象按一定算法进行整理。优点是内存碎片少,缺点是内存复制频率高、效率差。
  • 复制(Copying):将内存空间分为两个半区,同一时间只使用其中一个半区。每次回收将一个半区的存活对象复制到另一个半区。优点是内存碎片少,缺点是浪费一半内存。

回收算法差异:内存利用率、内存连续度、是否移动对象、时间开销

性能评估

评估指标:

  • 吞吐量(throughput):普通应用,单次GC耗时远小于网络延迟,因此更关注GC频率对吞吐量的影响。
  • 延迟(latency):少数应用需要实现毫秒级延迟,因此更关注单次GC耗时。

垃圾回收器

JDK 17提供4个垃圾回收器:

  • Serial
  • Parallel
  • Garbage-First (G1)
  • ZGC

命令行参数

  • -Xmssize:设置堆内存最小值和初始值。
  • -Xmxsize:设置堆内存最大值。服务端通常将-Xms和-Xmx设置成一样的值。
  • -Xsssize:设置线程栈内存大小。
  • -XX:+HeapDumpOnOutOfMemoryError:在发生OutOfMemoryError时,将堆dump到磁盘,用于排查OOM问题。

参考资料

https://docs.oracle.com/en/java/javase/17/gctuning/garbage-collector-implementation.html
https://tech.meituan.com/2020/11/12/java-9-cms-gc.html
https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html