本文是《深入理解Java虚拟机(第二版)》第三章的笔记
如何判断对象为垃圾对象
引用计数法
给对象添加一个引用计数器,每当有个对象引用它时,计数器加1;引用失效时计数器减1;为0时对象不可能被再引用。
没有使用的原因:很难解决对象之间相互循环引用的问题
可达性分析算法
看作为GC Roots的对象作为起始点,和它连通的是可用的,反之不可用。
如下情况的对象可以作为GC Roots:
- 虚拟机栈(栈桢中的本地变量表)、本地方法栈中JNI(Native方法)中的引用的对象
- 方法区中的类静态属性引用的对象
- 方法区中的常量引用的对象
当对象不可达时,会执行fianlize()
,但该方法自会被自动调用一次,有点像c++的析构函数,书上说最好别用。
引用的分类
- 强引用:
Objece obj = new Object()
,永远不会被垃圾搜集回收 - 软引用:
SoftReference
类实现,可以存活第一次回收,但第二次就GG - 弱引用:
WeakReference
类实现,第一次就GG - 虚引用:
PhantomReference
类实现,不能通过它取得实例,唯一作用就是当该对象被回收时会收到一个系统通知。
如何回收
垃圾收集算法
- 标记-清除算法:(老年代)先标记,再清除。缺点:效率低,内存碎片化
- 复制算法:(新生代)HotSpot虚拟机把内存分为Eden和2块Survivor区,把在Eden和Survivor中 存活的对象 复制到空闲的一块Survivor中。不够时可以向老年代担保。
- 标记-整理算法:(老年代)标记 -> 移动到一起 -> 清理
- 分代收集算法:把内存分为新生代和老年代。根据年代选则合适的算法。
垃圾收集器
新生代 | 老年代 | 特殊 |
---|---|---|
Serial(单线程) | Serial Old(单线程,CMS备胎) | G1(Region优先级回收) |
ParNew(多线程) | CMS(并发) | |
Parallel Scavenge(关注吞吐量) |
- 并行(Parallel):多条垃圾收集线程并行工作,但此时用户线程仍处于等待状态。
- 并发(Concurrent):用户线程与垃圾收集线程同时执行。
如何分配
以HosSpot收集器的分配和回收策略为例
- 优先分配在Eden
- 大对象直接进入老年代
- 长期存活的对象进入老年代
- 动态对象年龄判定
- 空间分配担保