JVM 辣鸡回收

垃圾回收算法

标记清除法

先标记出需要回收的对象,然后一次性回收。缺点:会产生内存碎片,并且效率也不高。

标记压缩法

先标记出需要回收的对象,然后让存活对象向一端移动,移动的过程中进行回收辣鸡。避免了内存碎片问题。

复制算法

把内存划分出相等的两块,每次只用其中一块。当一块用完了,就将还存活的对象移动到另一块内存上,然后把辣鸡清理掉。内存分配不用来考虑碎片问题,只需要顺序分配即可。缺点:总有一块内存闲着没事干。

为了形象生动可爱,我画了个图

..

垃圾回收器

串行收集器

串行辣鸡收集器只用一个单线程做所有工作,其内存占用空间大小也是所有辣鸡收集器里最低的。

  • 新生代辣鸡回收使用复制算法
  • 老年代使用标记压缩算法

并行收集器

 

并行收集器相对于串行收集器,使用了多线程来完成辣鸡回收的工作,但是同样也需要Stop-The-World。新生代和老年代的回收都是并行的。

(历史:刚引入的时候,新生代使用多线程,而老年代则是单线程进行辣鸡回收。随着堆的尺寸和老年代对象的数量和大小不断增长,老年代辣鸡回收的时间不断变长,增加了一个多线程的老年代收集器和多线程的新生代收集器同时使用的方式,由此得到了增强的并行辣鸡收集器)

  • -XX:+UseParallelGC  新生代使用并行收集器,老年代使用串行收集器
  • -XX:+UseParallelOldGC  新生代和老年代都使用并行收集器
  • 新生代使用复制算法
  • 老年代使用标记压缩算法

CMS收集器(Concurrent Mark Sweep)

 

在CMS辣鸡回收中,新生代的回收与并行辣鸡收集器很类似。它们是多线程的并且会使应用程序线程暂停。主要区别在于老年代的收集上。

CMS做辣鸡回收的时候与应用线程同时进行,除了少数的相对短暂的GC同步暂停,可以说是大多数情况是并发进行的。

CMS老年代收集活动从初始标记开始,这个阶段标记根可以直接关联到的对象,这个阶段是要暂停应用线程的。之后进入并发标记阶段,这个阶段标记所有对象,和应用线程一同运行。接着,进入重新标记阶段,这个阶段主要处理初始标记,并发标记过程中可能错过的对象,这个阶段是要暂停应用线程的。最后,并发清除启动,释放所有死亡对象所占用的空间。

  • 挑战1:要在应用消耗完Java的可用堆之前完成并发收集工作,因此选择一个合适的时机来启动这个并发收集工作尤为重要。
  • 挑战2:处理老年代中的空间碎片。如果老年代中空间碎片太小,无法容纳刚晋升上来的对象,因为CMS并发收集循环中并不执行压缩,所以可能导致CMS回过来使用串行GC,触发一次full收集,导致一个漫长的暂停。
  • 老年代主要使用标记清除算法。清理碎片显得很重要。
  • -XX:+UseCMSCompactAtFullCollection   垃圾收集完成后,进行一次内存碎片整理
  • -XX:CMSFullGCsBeforeCompaction  回收一定次数后,压缩一次内存

JDK 8中两个主要的并发收集器:
  并发标记扫描(CMS)收集器:此收集器适用于喜欢较短垃圾收集暂停且可以与垃圾收集共享处理器资源的应用程序。
  Garbage-First垃圾收集器:这种服务器式收集器适用于具有大内存的多处理器机器。它以高概率满足垃圾收集暂停时间目标,同时实现高吞吐量。

G1收集器(Garbage First)

 G1把Java堆拆成一系列分区,这样的话,在某一个时间段内,大部分辣鸡回收只在一个区内而不是整个堆中进行。区域大小可以从1 MB到32 MB不等,具体取决于堆大小。目标是不超过2048个分区。伊甸区,幸存区和老年代是这些地区的逻辑集合,并不是连续的。

一个新概念:新生代不再是一个连续内存块,一个分区既可以变成新生代,也可以变成老年代。

堆被划分为一组大小相同的堆区域,每个区域都是一个连续的虚拟内存区域。G1执行一个并发全局标记阶段,以确定整个堆中对象的活性。

标记阶段完成后,G1知道哪些区域大部分是空的。它首先收集这些区域,这通常会产生大量的自由空间。这就是为什么这种垃圾收集方法被称为Garbage-First。

G1将对象从堆的一个或多个区域复制到堆上的单个区域,并且在此过程中压缩并释放内存。这个过程是多线程执行,以减少暂停时间并提高吞吐量。因此,随着每次垃圾收集,G1不断努力减少碎片。这超出了以前两种方法的能力->CMS(Concurrent Mark Sweep)垃圾收集不进行压缩。并行压缩仅执行整堆压缩,这会导致相当长的暂停时间。

所有Eden区+幸存区=新生代

..

新生代的收集和前面的没啥区别,都要暂停应用线程。老年代比CMS的老年代收集还要与众不同。↓↓

一个G1并发周期包含:初始标记、并发根分区扫描、并发标记、重新标记和清除。

在G1中,一旦达到内存堆的占用阈值[yu zhi],一次并发stop-the-world方式的初始标记阶段就会被安排执行,在此阶段标记所有GC根,根是对象图的起点。这个阶段会跟着下一次新生代收集同时进行。然后进入并发根分区扫描,扫描和跟踪survivor分区里所有对象的引用,唯一的限制是在下一次GC前必须先完成扫描,因为一次新的GC会产生一个新的存活对象集合,它跟初始标记的存活对象是有区别的。

然后进入并发标记阶段,标记老年代中所有存活对象。当并发标记阶段结束,并行stop-the-world的重新标记阶段就被启动,标记那些因为在标记阶段同时执行的应用线程导致产生的错过的对象。重新标记结束,就执行清除阶段,优先回收没有任何存活对象的分区,然后把每个收集过辣鸡的分区中的存活对象转移到一个可用分区中,一旦存活对象被转移,那么这个分区(新生代或者老年代)就可以被回收为可用分区。

 G1最大的暂停时间来源于 新生代收集和混合收集(新生代和老年代一起)

猜你喜欢

转载自www.cnblogs.com/LUA123/p/9831729.html