有哪些垃圾回收算法
- 标记-清除算法:
- 标记:标记出可以回收的对象
- 清除阶段:回收被标记的对象所占用空间
(标记-清除算法之所以关键,是其他算法都是在此基础上改进而来)
优点: 实现简单、不需要对对象进行移动
缺点; 标记、清除过程效率低,产生大量不连续的内存碎片,提高了垃圾回收的频率
2.复制算法
- 将内存空间划分为两个相等的区域,每次只使用一个区域,垃圾收集时,遍历当前区域,把存活的对象复制到另外一个区域中,最后对当前区域进行回收。
优点: 按顺序分配内存即可,实现简单、运行高效、不考虑内存碎片
缺点: 可用内存大小缩小了一半,对象存活率高时会频繁进行复制
3.标记-整理算法
(新生代可以使用复制算法,但老年代不能选择复制算法,因为老年代的对象存活率会比较高,这样会有较多的复制操作,导致效率变低,这样说标记-清除算法可以应用到老年代,但是它效率不高,还会产生大量的内存碎片,因此出现了一种新的算法:标记-整理算法)
在标记可回收的对象后,将所有存活的对象压缩到内存的另一端,使得他们紧凑的排列在一起,然后对端边界以外的内存进行回收,/(已用和未用内存都各自一边了)
优点: 解决了内存碎片问题 缺点: 仍然需要对对象移动,在一定程度上降低了效率
4.分代收集算法 (目前大部分JVM所采用的方法,其核心思想就是根据对象存活的不同生命周期将内存划分为不同的域【新生代/老年代】,根据老年代的特点,每次垃圾回收只有少量对象需要被回收,新生代特点,每次垃圾回收都有大量垃圾需要被回收,因此根据不同选择算法)
新生代与复制算法 每次垃圾收集都能发现大批对象已死,只有少量存活,因此选择复制算法,只需要付出少量存活对象的复制成本就可以完成收集。目前大部分JVM的GC对于新生代都是采用复制算法。
老年代与标记复制算法 因为老年代对象存活率高,没有额外空间对它进行分配担保,必须采用标记-清理或标记-整理算法,不必进行内存复制,且直接腾出空闲内存。
垃圾收集器
java堆内存划分为:新生代、老年代;新生代主要使用复制和标记-清除算法;老年代主要使用标记-整理算法。 JVM虚拟机针对老年代、新生代分别提供了多种不同的垃圾收集器。
新生代:serial 、 parNew、parallel Scavenge 、 G1
老年代:CMS、serial old、parallel old、 G1
serial:单线程、简单高效(复制算法) -- 新生代
parnww:多线程,多核环境下,比serial更高效(复制算法) -- 新生代
parallel scavenge :多线程,追求高吞吐量,高效利用CPU。对后台应用交互相应要求不高的场景(复制算法) -- 新生代
seial old: 单线程(标记-整理) -- 老年代
parallel old:多线程,吞吐量优先(标记-清理) -- 老年代
CMS:多线程,最短回收停顿时间为目标的收集器,高并发、低停顿的特点(标记-清除) -- 老年代
G1: 多线程(标记-整理) -- 可用于整个java堆
Stop-the-world
是JVM中垃圾回收过程中一种现象,指在进行垃圾回收时,所有应用程序线程都会暂停执行,直到垃圾回收完成。(这种暂停是为了确保垃圾回收器能够准确地识别哪些对象是存活地,哪些对象是死的可回收的)
通常垃圾回收分为几个阶段,某些阶段可能需要STW事件,以保证内存状态的一致性。但是它可能会对应用性能造成负面影响,尤其是要求低延迟的应用场景下
为了减轻STW事件的影响,现代JVM采用多种技术来优化垃圾回收过程:
并发垃圾回收:允许垃圾回收的一些阶段与应用程序同时进行 增量式垃圾回收:将整个垃圾回收过程分割成多个小的任务,并在这些任务之间穿插者应用程序代码的执行。 并行垃圾回收:利用多核CPU的优势,将垃圾回收工作,分布在多核CPU上并行执行
随着JVM技术的发展,G1、ZGC、shenandoah等新式垃圾回收器进一步减少了STW事件的发生频率以及其持续时间。