Java虚拟机垃圾回收算法及垃圾回收器

垃圾回收:对象被创建后,当不需要使用时不会自动消失且会一直占用系统内存直到应用程序结束,造成部分空间无法被利用,不进行回收将会内存溢出

引用计数法

当一个对象被另一对象引用则计数器就加1,引用失效就减1,为0就回收当前对象

缺点:加一减一给CPU带来额外负担,无法处理两个无用对象互相引用(即a引用b,b引用a,计数器均为1,但a、b均不需要使用)的情况

标记清除法

标记阶段:从根对象开始标记可到达的对象,未被标记即为垃圾对象
清除阶段:将未被标记的对象进行清除

缺点:带来内存空间碎片,增加大对象存放的时间或者可能性,部分空间可能无法使用

复制算法

将内存分为连个区域A、B,使用A区域进行内存回收时,判断A中需要继续保存的对象,将这些对象复制进B,对A区域进行全部回收,开始使用B

缺点:内存分为两个区域,降低了内存最大可用程度,垃圾对象远远少于存活对象时需要复制大量对象

标记压缩法

将所有使用的对象进行标记,压缩到内存区域的一端,将边界外所有对象清除,避免了碎片,不需要将内存折半

分代算法

  • 新生代:新生代保存大量刚创建的对象,垃圾对象较多,存活对象少,适合采用复制算法
  • 老年代:采用标记清除法、标记压缩法

    新生代的复制算法

    • 所有刚创建的对象位于Eden区,经历一次GC后(若此时From正在被使用),将Eden区中需要存活的对象放入to区,from中需要存活的对象GC年龄加1后放入to区(若年龄大于老年代的要求即放入老年代),其他对象回收
    • Eden区中的对象可能被老年代中对象引用,可根据卡表标记老年对象是否持有新生代对象而不需要GC时扫描每一个老年对象

分区算法

将堆空间划分成连续的不同小区间,独立使用,独立回收,不需要对整个堆进行回收,降低GC耗时停顿(GC时暂停所有操作)

垃圾回收器

  • 新生代串行回收器:单线程,独占式(GC线程执行时,应用程序停止),复制算法
  • 老年代串行回收器:单线程,独占式,标记压缩法
  • 新生代ParNew回收器:多线程回收,独占式,复制算法
  • 新生代Parallel回收器:多线程,独占式,复制算法,关注系统吞吐量(GC吞吐量大则GC停顿时间(STOP THE WORLD)大)
  • 老年代Parallel回收期:多线程,独占式,标记压缩法,吞吐量
  • CMS回收器:多线程,非独占式,标记清除法,关注停顿时间,易造成碎片,多次GC后需要整理内存空间
  • G1回收器:多线程,分代垃圾回收器,采用分区算法(不要求eden、survivor、old连续),部分工作可以和应用程序同时执行,回收后复制对象,减小碎片,可以只选择部分区域进行GC

  • 对象何时进入老年代?堆空间新创建的对象均为于Eden区,老年对象将进入老年代(经历15次以上必进入老年代,未到15次也可能由于survivor区内存不够直接放入老年代)
  • 对象创建?先进行逃逸分析,进行栈上分配,再采用TLAB(线程本地分配,防止多线程竞争分配,效率下降),若对象较大,则判断是否直接放入老年代,否则放入eden