基础
基本概念
- 弱分代假说(weak generational hypothesis):多数对象的生命周期很短。
- 分代回收(generational collection):基于弱分代假说,将内存空间分为多个区域(代),在每一代填满时执行垃圾回收;不同代使用不同的垃圾回收算法。
内存结构
Java程序内存结构:
- 堆内存(Heap Space)
- 新生代(Young Gen)
- Eden
- Survivor 0/1
- 老生代(Old Gen)
- 新生代(Young 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