1、标记-清除算法:Mark-Sweep
标记清除算法:是将垃圾回收分为2个阶段,分别是标记和清除。
1.根据可达性分析算法得出的垃圾进行标记
2.对这些标记为可回收的内容进行垃圾回收
可以看到,标记清除算法解决了引用计数算法中的循环引用的问题,没有从root节点引用的对象都会被回收。
同样,标记清除算法也是有缺点的:
-
效率较低,标记和清除两个动作都需要遍历所有的对象,并且在GC时,需要停止应用程序,对于交互性要求比较高的应用而言这个体验是非常差的。
-
(重要)通过标记清除算法清理出来的内存,碎片化较为严重,因为被回收的对象可能存在于内存的各个角落,所以清理出来的内存是不连贯的。
2、标记-整理算法:Mark-Compact
上述的 标记-清除 算法会产生内存区域使用的间断,所以为了将内存区域尽可能地连续使用, 标记-整理 算法应运而生。标记-整理 算法也是由两步组成,标记 和 整理。
和标记清除算法一样,先进行对象的标记,通过GC Roots节点扫描存活对象进行标记,将所有存活对象往一端空闲空间移动,按照内存地址依次排序,并更新对应引用的指针,然后清理末端内存地址以外的全部内存空间。
1)标记垃圾。
2)需要清除向右边走,不需要清除的向左边走。
3)清除边界以外的垃圾。
优缺点同标记清除算法,解决了标记清除算法的碎片化的问题,同时,标记压缩算法多了一步,对象移动内存位置的步骤,其效率也有有一定的影响。
与复制算法对比:复制算法标记完就复制,但标记整理算法得等把所有存活对象都标记完毕,再进行整理
3、复制算法:Copying
无论是标记-清除算法还是标记-整理算法,都会涉及句柄的开销或是面对碎片化的内存回收,所以,复制算法 出现了。
复制算法将内存区域均分为了两块(记为S0和S1),而每次在创建对象的时候,只使用其中的一块区域(例如S0),当S0使用完之后,便将S0上面存活的对象全部复制到S1上面去,然后将S0全部清理掉。复制算法主要被应用于新生代,它将内存分为大小相同的两块,每次只使用其中的一块。在任意时间点,所有动态分配的对象都只能分配在其中一个内存空间,而另外一个内存空间则是空闲的。
1)将内存区域分成两部分,每次操作其中一个。
2)当进行垃圾回收时,将正在使用的内存区域中的存活对象移动到未使用的内存区域。当移动完对这部分内存区域一次性清除。
3)周而复始。
优点:
-
在垃圾对象多的情况下,效率较高
-
清理后,内存无碎片
缺点:
-
分配的2块内存空间,在同一个时刻,只能使用一半,内存使用率较低
4、分代收集算法
实际上,java中的垃圾回收器并不是只使用的一种垃圾收集算法,当前大多采用的都是分代收集法。一般根据对象存活周期的不同,将内存分为几块,一般是把堆内存分为新生代和老年代,再根据各个年代的特点选择最佳的垃圾收集算法。主要思想如下:
-
新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要复制少量对象以及更改引用,就可以完成垃圾收集。
-
老年代中,对象存活率比较高,使用复制算法不能很好的提高性能和效率。另外,没有额外的空间对它进行分配担保,因此选择标记-清除算法或标记-整理算法进行垃圾收集。
-
对于新生代,内部又被分为了三个区域。Eden区,S0区,S1区【8:1:1】
当对新生代产生GC:MinorGC【young GC】
当对老年代代产生GC:Major GC
当对新生代和老年代产生FullGC: 新生代 + 老年代完整垃圾回收,暂停时间长,应尽力避免
工作机制
-
新创建的对象,都会先分配到eden区
-
当伊甸园内存不足,标记伊甸园与 from(现阶段没有)的存活对象
-
将存活对象采用复制算法复制到 to 中,复制完毕后,伊甸园和 from 内存都得到释放
-
经过一段时间后伊甸园的内存又出现不足,标记eden区域to区存活的对象,将存活的对象复制到from区
-
当幸存区对象熬过几次回收(最多15次),晋升到老年代(幸存区内存不足或大对象会导致提前晋升)
MinorGC、 Mixed GC 、 FullGC的区别是什么
-
MinorGC【young GC】发生在新生代的垃圾回收,暂停时间短(STW)
-
Mixed GC 新生代 + 老年代部分区域的垃圾回收,G1 收集器特有
-
FullGC: 新生代 + 老年代完整垃圾回收,暂停时间长(STW),应尽力避免?
名词解释:
STW(Stop-The-World):暂停所有应用程序线程,等待垃圾回收的完成