JAVA垃圾回收机制 -(算法和收集器)
一. 标记清除法(Mark-Sweep)
最基础的垃圾回收算法,分为标记和清除两步。将要清除的对象进行标记然后直接清除掉,这样就就大大节省了空间了。
最大的问题:会导致内存碎片化严重,可能导致大对象找不到可以利用的空间。
当内存被耗尽的时候,GC线程会被触发,并将程序暂停 1.标记存活对象,2. 全部清除未被标记对象,接下来便让程序恢复运行。
二. 复制法(copying)
为了解决 Mark-Sweep 算法内存碎片化的缺陷而被提出的算法。
按内存容量将内存划分为等大小的两块,每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存块清掉。
最大问题:内存利用率低,存活对象增对时,效率会大大降低。
三. 标记整理法(Mark-Compact)
结合了以上两个算法,标记阶段和 Mark-Sweep 算法相同, 标记后不是清理对象,而是将标记为存活对象移向内存的一端(按照内存地址依次排列)。然后清除端边界外的对象。
缺点:整理存活对象,耗费资源,效率低。
四. 分代收集法
目前大部分 JVM 此法,其核心思想是,根据对象生命周期的不同,将gc堆划分为老生代和新生代。
每次垃圾回收时,新生代都有大量垃圾需要被回收,而老生代只有少量对象需要被回收,因此可以根据不同区域选择不同的算法。
1. 新生代使用Copying算法(因为每次gic回收较多的数据,需要复制的较少)
GC 对于新生代都采取 Copying算法,由新生代的特点知道回收要复制的数据比较少。一般将新生代分较大的 Eden 空间和两个较小的 Survivor 空间(From Space, To Space)【非1:1】,每次使用Eden 空间和其中的一块 Survivor 空间,当进行回收时,将该两块空间中还存活的对象复制到另一块 Survivor 空间中。
2. 老生代使用标记整理算法(因为每次gc回收较少的数据,需要整理的少)
(1)方法区用来存储 class 类、常量和方法描述等。对方法区的回收主要包括废弃常量和无用的类。
(2)对象的内存分配主要在新生代的 Eden Space 和 Survivor Space 的 From Space(Survivor 目前存放对象的那一块),少数情况会直接分配到老生代。
(3)当新生代的 Eden Space 和 From Space 空间不足时就会发生一次 GC,进行 GC 后, Eden区 和 From 区的存活对象会被挪到 To区,然后将 Eden区和 From区 进行清理。
(4) 如果To Space 无法足够存储某个对象,则将这个对象存储到老生代。
(5) 在进行 GC 后,使用的便是 Eden Space 和 To Space 了,如此反复循环。
(6)当对象在 Survivor 区躲过一次 GC 后,其年龄就会+1。 默认情况下年龄到达 15 的对象会被移到老生代中。
五. 分区收集算法
分区算法则将整个堆空间划分为连续的不同小区间, 每个小区间独立使用, 独立回收. 这样做的好处是可以控制一次回收多少个小区间, GC 所产生的停顿。
六、垃圾回收器
CMS 收集器
年老代,多线程,标记清除的垃圾收集器。最主要目标是获取最短垃圾回收停顿时间。
1. 初始标记(停顿)
2. 并发标记(不停顿)
3. 重新标记(停顿)
4. 并发清除(不停顿)
当产生大量不连续的内存碎片会导致分配大内存对象时,无法找到足够的连续内存,从而需要提前触发另一次Full GC动作。
"-XX:+UseCMSCompactAtFullCollection"
使得CMS出现上面这种情况时不进行Full GC,而开启内存碎片的合并整理过程,但合并整理过程无法并发,停顿时间会变长;
————————————————