文章目录
1. 如何确定垃圾
如何确定JVM内存中的垃圾对象?
1.1 引用计数法(reference count)
Java中,引用和对象是有关联的,如果要操作某个对象则必须使用引用进行。
给对象上增加引用标记,有几个引用指向它,就给他标记几。
因此,如果某个对象的引用计数为0,则说明该对象是垃圾。
但是,无法处理循环引用场景,一堆垃圾对象
1.2 根可达算法(root searching)
哪些对象是Roots对象?
- main函数栈帧中的对象 = 根对象
- 静态变量指向的对象
- .class在load到内存之后,就会马上初始化静态变量,这个静态变量指向的对象 = 根对象
- 常量池 - 常量池中的class会用到别的class的对象 = 根对象
- JNI - 调用Native的本地方法中用到的对象 = 根对象
Java中通过定义一系列的 GC Roots 对象作为搜索的起点,如果在 GC Roots 对象和目标对象之间没有可达的路径,则称为不可达。
当一个对象被这个算法标记两次之后,视为垃圾对象,面临回收。
which instances are roots?
JVM Stack、NativeMethodStack、run-timeConstantPool、StaticReferenceInMethodArea、Clazz
一个程序启动之后,马上需要的对象 = 根对象
2. 垃圾清除算法
标记清除算法(Mark-Sweep)
原理:分为两个阶段:标记、清除
- 标记:标记出需要回收的对象;
- 清除:回收垃圾对象所占用的内存空间
问题:导致内存碎片化严重,后续可能导致大对象不能找到可利用的空间
复制算法(Copying)
原理:
按内存容量,将内存划分为大小相等的两块,每次只使用其中的一块,当这一块内存满后,将存活的对象复制到另一块上,将这一块内存清掉。
特点:
效率高,不易产生内存碎片
问题:
可用内存被压缩到了原本的一半,且存活对象增多的化,Copying算法的效率会大大降低
标记压缩算法(Mark-Compact)
原理:
结合了Copying和Mark-Sweep算法,分为两个阶段,标记阶段,和移动清理阶段