Java将堆内存分为3大部分:新生代、老年代和永久代,其中新生代又进一步划分为Eden、S0、S1(Survivor)三个区。结构以下图所示:算法
Java将堆内存分为3大部分:新生代、老年代和永久代,其中新生代又进一步划分为Eden、S0、S1(Survivor)三个区。结构以下图所示:多线程
程序中new出来的对象会在新生代里的Eden区里面分配空间,若是存活时间足够长将会进入Survivor区,进而若是存活时间再长,还会被提高分配到老年代里面。持久代里面存放的是Class类元数据、方法描述等。并发
1.S0和S1是两个大小相等的区域,分配内存空间只会在其中某一个进行,另一个空间是用来辅助进行新生代进行垃圾回收的,由于新生代的垃圾回收策略基于复制算法,其思想是将Eden区及两个Survivor中的某个区,如S0区里面须要存活的对象复制到另一个空的Survivor区,如S1区,而后就能够回收Eden和S0区域里面的死亡对象。下一次回收就对调S0和S1两个区的角色,S1用来存放存活对象而S0用来辅助回收垃圾,如此循环利用。 .net
2.有些文章并不将永久代归入Java堆内存。其实永久代就是咱们所说的方法区,而方法区常常被称为Non-Heap(非堆)。仅仅在HotSpot虚拟机的实现中才将GC分代收集扩展至方法区,或者说使用永久代来实现方法区,对于其余的虚拟机是不存在永久代这个概念的。 线程
3.并不是全部的对象建立都会在Eden区中分配内存空间。对于Serial和ParNew垃圾收集器,经过指定-XX:PretenureSizeThreshold={size}来设置超过这个阈值大小的对象直接进入老年代。对象
垃圾回收主要针对Java堆内存中的新生代和老年代,也正由于新生代和老年代结构上的不一样,因此产生了分代回收算法,即新生代的垃圾回收和老年代的垃圾回收采用的是不一样的回收算法。针对新生代,主要采用复制算法,而针对老年代,一般采用标记-清除算法或者标记-整理算法来进行回收。blog
复制算法的思想是将内存分红大小相等的两块区域,每次使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另外一块区域上,而后对该块进行内存回收。内存
这个算法实现简单,而且也相对高效,可是代价就是须要将牺牲一半的内存空间用于进行复制。有研究代表,新生代中的对象98%存活期很短,因此并不须要以1:1的比例来划分整个新生代,一般的作法是将新生代内存空间划分红一块较大的Eden区和两块较小的Survivor区,两块Survivor区域的大小保持一致。每次使用Eden和其中一块Survivor区,当回收的时候,将还存活的对象复制到另一块Survivor空间上,最后清除Eden区和一开始使用的Survivor区。假如用于复制的Survivor区放不下存活的对象,那么会将对象存到老年代。get
HotSpot虚拟机默认Eden和Survivor的大小比例是8:1:1,也就是说新生代中牺牲掉10%的空间而不是一半的空间。虚拟机
标记-清除(Mark-Sweep)算法分为两个阶段:
标记
清除
在标记阶段将标记出须要回收的对象空间,而后在下一个阶段清除阶段里面,将这些标记出来的对象空间回收掉。这种算法有两个主要问题:一个是标记和清除的效率不高,另外一个问题是在清理以后会产生大量不连续的内存碎片,这样会致使在分配大对象时候没法找到足够的连续内存而触发另外一次垃圾收集动做。
标记-整理(Mark-Compact)算法有效预防了标记-清除算法中可能产生过多内存碎片的问题。在标记须要回收的对象之后,它会将全部存活的对象空间挪到一块儿,而后再执行清理。
标记-整理一般会在标记-清除算法里面做为备选方案,为了防止标记-清除后产生大量内存碎片而没法为大对象分配足够内存的状况
由于新生代和老年代采用回收算法的不一样,垃圾收集器相应地也分为新生代收集器和老年代收集器。其中新生代收集器主要有Serial收集器、ParNew收集器和Parallel Scavenge收集器。老年代收集器主要有Serial Old收集器、Parallel Old收集器和CMS收集器。固然还包括了一款全新的、新生代老年代通用的G1收集器。
上图展现了7种做用于不一样分代的收集器,若是两个收集器之间存在连线,就说明它们能够搭配使用。
Serial收集器做用于新生代,是一个单线程收集器,基于复制算法实现。在进行垃圾回收的时候仅使用单条线程而且在回收的过程当中会挂起全部的用户线程(Stop The World)。Serial收集器是JVM client模式下默认的新生代收集器。
特别注意,Stop-The-World会挂起应用线程,形成应用的停顿。
ParNew收集器做用于新生代,是一个多线程收集器,基于复制算法实现。相对于Serial收集器而言,在垃圾回收的时候会同时使用多条线程进行回收,可是它跟Serial收集器同样,在回收过程当中也是会挂起全部的用户线程,从而形成应用的停顿。
Parallel Scavenge收集器一样做用于新生代,而且也是采用多线程和复制算法来进行垃圾回收。Parallel Scavenge收集器关注的是吞吐量,即便得应用可以充分使用CPU。它与ParNew收集器同样,在回收过程会挂起全部的用户线程,形成应用停顿。
Serial Old收集器做用于老年代,采用单线程和标记-整理算法来实现垃圾回收。在回收垃圾的时候一样会挂起全部用户线程,形成应用的停顿。通常来讲,老年代的容量都比新生代要大,因此当发生老年代的垃圾回收时,STW经历的时间会比新生代所用的时间长得多。该收集器是JVM client模式下默认的老年代收集器。
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,采用多线程和标记-整理算法来实现老年代的垃圾回收。这个收集器主要是为了配合Parallel Scavenge收集器的使用,即当新生代选择了Parallel Scavenge收集器的状况下,老年代能够选择Parallel Old收集器。
CMS(Concurrent Mark Sweep)收集器是一款真正实现了并发收集的老年代收集器。CMS收集器以获取最短回收停顿时间为目标,采用多线程并发以及标记-清除算法来实现垃圾回收。CMS只在初始化标记和从新标记阶段须要挂起用户线程,形成必定的应用停顿(STW),而其余阶段收集线程均可以与用户线程并发交替进行,没必要挂起用户线程,因此并不会形成应用的停顿。CMS收集器能够最大程度地减小因垃圾回收而形成应用停顿的时间。
G1收集器的优点:
(1)并行与并发
(2)分代收集
(3)空间整理 (标记整理算法,复制算法)
(4)可预测的停顿