垃圾回收算法:
垃圾标记阶段:主要是为了判断对象是否存活。
一般有两种方式:引用计数算法和可达性分析算法。
①引用计数算法:对象被引用则+1,引用失效则-1,为0则可被回收。
缺点:空间、时间的开销大,无法处理循环引用的问题
②可达性分析算法(java使用):以根对象集合(GCRoots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否直接或间接可达,走过的路径叫做引用链。
GC Roots的选择:
(两栈两方法)
虚拟机栈中引用的对象
本地方法栈内JNI(通常说的本地方法)引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
(其他)
所有被同步锁synchronized持有的对象
虚拟机内部的引用。
GC进行时必须“Stop The World”的一个重要原因:在可达性分析算法中,枚举根节点是必须要停顿的,分析必须要在一个快照中进行。
finalize()--->对象销毁前的回调函数
对应的三种状态:
- 可触及:从根节点开始可到达这个对象。
- 可复活:对象的所有引用都被释放,但对象可能在finalize()中复活。
- 不可触及:对象的finalize()被调用,但未复活,那么就会进入不可触及状态。不可触及的对象可被回收。
两次标记:
引用链标记+finalize()方法调用标记-------->两次都标记以后,进行垃圾回收
算法:
标记-清除算法(Mark-Sweep)
标记:Collector从引用根节点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。
清除:Collector对堆内存从头到尾进行线性的遍历,如果发现某个对象在其Header中没有标记为可达对象,则将其回收
缺点:内存区域分散
需要维护一个空闲列表(如果内存规整:采用指针碰撞的方式进行内存分配;如果内存不规整:虚拟机需要维护一个空闲列表,采用空闲列表分配内存)
复制算法(Copying)
将活着的内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收(新生代里面就用到了复制算法,Eden区和S0区存活对象整体复制到S1区)
缺点:内存减半
标记-压缩算法(Mark-Compact)
标记:Collector从引用根节点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。
压缩:将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间。)
缺点:速率低
分代收集理论:
年轻代:复制算法
老年代:由标记-清除或者是标记-清除与标记-整理的混合实现。
增量收集算法:
目的:为了解决STW的问题
过程: 让垃圾收集线程和应用程序线程交替执行。每次,垃圾收集线程只收集一小片区域的内存空间,接着切换到应用程序线程。依次反复,直到垃圾收集完成。
优缺点:线程切换和上下文转换的消耗,会使得垃圾回收的总体成本上升,造成系统吞吐量的下降。
分区算法:
分代算法将按照对象的生命周期长短划分成两个部分,分区算法将整个堆空间划分成连续的不同小区间。每一个小区间都独立使用,独立回收。这种算法的好处是可以控制一次回收多少个小区间。