引用计数法
引用计数法:有一个地方引用对象,计数加一,当计数为零表示可以垃圾回收;
缺点就是难以解决对象之间的循环引用问题
可达性分析算法
- java虚拟机的垃圾回收器采用可达性分析来探索所有存活的对象。它从一系列GCRoots出发,边标记边探索所有被引用的对象。
- 从GC Root对象为起点,看是否能沿着引用链找到该对象,找不到,表示可以回收。
- GC Root对象包括桟帧中的局部变量、方法区中的静态变量、方法区中的常量等。
- 为了防止在标记过程中堆桟的状态发生改变,应用程序的线程全部停止,暂停其他的非垃圾回收线程。
- 并不是让其他线程停下,而是找到一个稳定的执行状态。在这个状态下,Java虚拟机的堆桟不会发生变化。就可以执行可达性分析。
垃圾回收算法
- 标记清除
- 第一遍标记、第二遍收集。缺点是会产生内存碎片,碎片过多,仍会使得连续空间少。
- 标记整理
- 第一遍标记,第二遍整理,整理是指存活对象向一端移动来减少内存碎片,相对效率较低。
- 复制
- 开辟两份大小相等空间,一份空间始终空着,垃圾回收时,将存活对象拷贝进入空闲空间,优点是不会有内存碎片,但占用空间多。
分代垃圾回收
- 尝试在伊甸园分配
- 对象优先在『伊甸园』分配,当『伊甸园』没有足够的空间时,触发 Minor GC ,将『伊甸园』和『幸存区 From』中仍然存活的对象利用 复制算法 移入『幸存区 To』,然后交换『幸存区 From』和『幸存区 To』的位置。
- 大对象直接晋升到老年代
- 多次存活的对象
- 在幸存区历经多次 GC 还存活的对象会晋升至老年代,默认晋升的阈值是 15,也就是说只要经历 15 次回收不死,肯定晋升,但注意如果目标 survivor 空间紧张,也不必等足 15 次,可以提前晋升。
- 老年代连续空间不足,触发Full GC。
垃圾回收器的作用
释放和重用资源是垃圾回收算法的具体实现
- Serial收集器(复制算法):新生代单线程收集器,标记和清理都是单线程,优点是简单高效;
- ParNew收集器 (复制算法):新生代收并行集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现;
- Parallel Scavenge收集器 (复制算法):新生代并行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 用户线程时间/(用户线程时间+GC线程时间),高吞吐量可以高效率的利用CPU时间,尽快完成程序的运算任务,适合后台应用等对交互相应要求不高的场景;
- Serial Old收集器 (标记-整理算法):老年代单线程收集器,Serial收集器的老年代版本;
- Parallel Old收集器 (标记-整理算法):老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本;
- CMS(Concurrent Mark Sweep)收集器(标记-清除算法):老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间
- G1(Garbage First)收集器 (标记-整理算法):Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片
垃圾回收算法的底层原理(新生代、老年代)
标记清除
首先标记出所有需要回收的对象,在标记完成后统一回收掉被标记的对象 (老年代)
- 优点:实现简单,不需要对象进行移动
- 缺点:第一个是执行效率不稳定,第二个是内存空间的碎片化问题
- 标记复制
将可用内存按容量划分为大小相等的两块,每次使用其中的一块,这一块用完了就将还存活者的对象复制到另一块上面 (新生代)
- 优点:按顺序分配内存即可,实现简单、运行高效,不用考虑内存碎片
- 缺点:内存缩小到原来的一半.
- (eden区和幸存区大小比例是8:1)
标记整理
让所有存活的对象都移向内存空间的一端,然后直接清理掉边界以外的内存 (老年代)
- 优点:解决了标记-清理算法存在的内存碎片问题
- 缺点:仍需要进行局部对象移动,一定程度上降低了效率