JAVA-JVM-GC入门

1.什么是GC?

GC-Garbage collection,意为垃圾回收,在JVM中就是对不需要使用的内存空间进行回收, 这个过程就叫做GC回收.

2.GC的基础

2.1 GC的分类 Minor GC、Major GC和Full GC

1.Minor GC

从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。

  • 什么时候会触发Minor GC?

当JVM无法为一个新对象分配内存空间时会触发(例如Eden区域满了)

  • Minor Gc回收的是哪里的垃圾?

绝大多数的对象都是在Eden出生的,而Eden又属于新生代.

所以 Minor GC 的情况就相当清楚了——每次 Minor GC 会清理年轻代的内存。

2.Major Gc/Full Gc:

Major GC 是清理老年代空间,通常Major GC会伴随着至少一次的Minor GC(Major回收效率为Minor的十分之一)

Full GC 是清理整个堆空间—包括年轻代和老年代。

2.2 新生代和老年代

在我们对GC了解之前,先要了解几个概念.

堆区中的空间分布:

对内存空间进行分代,是为了优化GC的性能,将长期存活的放在一边,将不确定存活时期的放在一边,分别称其为新生代和老年代.

1.新生代(young)

  • 将新生代又划分为三个区域,eden,survivor 1,survivor 2.

新生代被划分为这三个区域,空间比例为8:1:1

1)Eden:内存占比最大,对象在此生成

2)survivor1与survivor2: 在GC过后每次将Eden与Survivor1中存活的对象,复制到Survivor2中.

  • 什么样的对象可以进入新生代:

大多数情况下,对象会在新生代EDEN中进行分配,当Eden中空间不足时,会对对其进行Minor GC操作.

回收效率:新生代回收速度快

2.老年代(old):

老年代的对象存活时间都比较长.

  • 什么样的对象可以进入老年代?

1)大对象直接进入老年代:大对象是指需要大量连续内存空间的对象,例如长字符串以及数组.

2)长期存活的对象进入老年代:JVM为了识别新对象与老对象,会为每一个对象设置一个Age的count,如果对象在eden出生并且经过第一次新生代GC(Minor GC)仍然存活,并且能被survivor容纳,就会被移动到survivor中,并且将Age设为1,当年龄增加到一定程度(default:15)就会晋升到老年代.

3)动态年龄判定:如果survivor空间中相同年龄的所有对象大小综合大于survivor空间的一般,大于等于这个年龄的对象可以直接进入老年代,无视第二条的默认年龄设置.

回收效率:老年代回收效率大概是新生代的十分之一.

要对内存进行合理的回收,需要解决三个问题,带着问题往下看,应该会有所理解.

1.哪些内存需要回收?

2.什么时候对其进行回收?

3.怎么进行回收操作.?

3.GC的算法

1.标记-清除算法:

标记-清除算法为最基础的收集算法,算法分为标记和清除两个阶段:

1.执行步骤:

1)首先标记出所有要回收的对象.

2)对标记的对象进行统一回收.

2.缺点:

1)效率不高

2)会产生大量不连续的内存空间,会导致分配大对象的时候出现问题.

2.复制算法:

为了解决上述的效率问题,复制算法随之而生.

1.执行步骤:

1)将可用内存空间划分为相等的A,B两块,每次使用其中一块.

2)当A空间使用完毕,将存活对象复制到B空间,将A空间内存统一清除整理.

2.缺点:

缺点可想而知,我们每次可以使用的内存空间仅为一半,虽然大大增加了GC的效率,但是付出的代价未免太高了一些.

改良:经过IBM公司研究表明,由于新生代对象朝生夕死,存活时间普遍不长,故将其内存空间分为Eden和两块survivor空间,比例为8:1:1, 也就是上述内存空间分配的由来,GC时将survivor复制到to survivor中, 进行复制算法.

分级担保:由于无法保证每次存活的对象都小于等于10%,所以当超过10%的时候需要依赖其他内存(如老年代),也就是额外空间.

3.标记-整理算法:

复制收集算法在对象存活率比较高的时候就会进行较多的赋值操作,效率会降低,如果使用8:1:1的分配比例时,需要额外空间进行担保,故此老年代并不能选用复制算法进行GC.

根据老年代对象存活时间的特点:标记-整理算法出现了.

标记整理算法与标记清除算法思路相同,但是后续步骤不同.

1.执行步骤:

1)标记存活对象

2)将存活对象向同一端移动

3)对端边界外的内存进行统一清理,这样获得的内存空间就是完整连续的.

ps:标记-整理与标记-清除算法的不同点就在于存活对象移动这一点

4.分代收集算法:

根据对象存活的时间进行分类,选择最有效率GC方法进行GC,现在我们都是采用分代收集进行内存回收.

分代收集就是将堆分为新生代和老年代.

新生代:如果发现每次大量对象死亡那么就选择复制算法,

老年代:存活时间比较长,没有额外空间分配担保,必须使用标记-清理或者标记-整理方法.

4.GC收集器类型

算法是GC方法的方法论,而这里GC收集器就是对上述GC方法的实现.

GC收集器分为7种:

1.新生代:

  • serial
  • ParNew
  • Parallel Scavenge

2.老年代

  • CMS
  • Serial Old(MSC)
  • Parallel Old

3.G1:单拿出来说是因为它不分新老,全区域覆盖.


新生代内存收集

1)serial:

特点:

1.单线程

2.效率高

3.缺点:在GC时需要停止所有线程.

使用算法:

新生代:复制算法

老年代:标记-整理算法

执行过程:

1.暂停所有用户线程(stop the world,作者第一次从书上看到也感觉中二病都要发作了..)

2.进行新生代GC

3.进行老年代GC

优势和缺陷:

优势:效率高,能与CMS进行配合

劣势:单线程,在回收较大内存空间的时候Stop the world时间较长,会造成极差的用户体验.

2)ParNew:

ParNew可以说是serial的多线程版本,除了使用多线程进行GC外,其余配置全部与serial一样.

特点:

1.多线程

2.在GC时需要停止所有线程.

执行过程:

1.暂停所有用户线程

2.进行新生代GC

3.进行老年代GC

优势:

1.在多CPU多线程的情况下可以充分利用资源,增加GC效率.

2.能与CMS配合

劣势:

1.在GC时需要停止所有线程.

2.在单线程的情况下效率没有serial高.

并行与并发:

并行:指多条线程同时进行GC,但是用户仍然需要等待.

并发:用户线程与GC同时进行,GC单独占用一个CPU进行GC,或者用户线程与GC线程交替执行.

3)Parallel Scavenge

Parallel Scavenge是并行收集器,同时也是多线程收集器,算法也与上边无异.

特点:

1.这种收集器关注的是吞吐量,其他搜集器关注的是停顿时间(stop the world的时间)

吞吐量:

吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)

也就是说,吞吐量越高,GC的时间就越短.

乍一看好像与上边两种方法没什么区别,停顿时间短了,吞吐量不就上去了吗?

实际上,说关注的是吞吐量是因为这种搜集器提供了两种参数供我们使用.

控制最大GC时间:MaxGCPauseMills

这里GC的时间是以毫秒为单位,GC时间的缩短是以牺牲吞吐量和新生代空间来换取的.

举个栗子:

若将停顿时间减少,由原来的每10秒搜集一次,停顿100毫秒,改为每5秒搜集一次,停顿时间为70毫秒,但从停顿时间间隔上是减少了.

整体的运行时间却增加了.

直接设置吞吐量大小:GCTimeRatio

这个设置的值就相当于GC占总时间的比率,设定范围为整数的(0,100)

老年代收集器:

1.serial Old

这个收集器是上边serial的老年代版本,同样是单线程收集器,主要意义是给在client模式下的虚拟机使用.

工作原理与serial相同.

特性:

与Parallel scavenge搭配使用

2.Parallel Old

这个收集器是Parallel scavenge的老年代版本,同样使用的是多线程+标记整理算法,JDK1.6后开始提供.

特性:

与Parallel scavenge搭配使用.

3.CMS:

CMS收集器是以获取最短回收停顿时间为目标的收集器,应用在JAVA的网站或者B/S系统的服务端上,重视响应速度,基于标记-清除方法.

执行过程:

1.初始标记:标记一下GC Roots能关联到的对象,速度很快
2.并发标记:GC ROOTS TRACING的过程
3.重新标记:修正在并发期间因程序继续运作导致的标记变动.
4.并发清除

其中1与3步骤仍然需要停止所有用户线程,而2与4是并发的情况,并不需要停止用户线程.

缺点:

1.在并发阶段会导致程序变慢,
默认启动线程数为(CPU数量+3)/4,当CPU数量较少的时候会给予系统比较大的负担.

2.无法处理浮动垃圾.可能会导致并发故障(concurrent mode failure)从而导致另外一次FULL GC.

浮动垃圾:CMS在并发阶段程序还在运行,会不断有新的垃圾产生,本次无法清除的垃圾,就是浮动垃圾.

3.由于使用的是标记-清除算法,会产生不连续的内存空间碎片,从而触发FULL GC

G1收集器

特点: 老幼通吃

1.并行并发

2.分代收集

3.空间整合(不会产生碎片内存空间)

4.可预测停顿(可以预计GC回收时间,不会超过峰值)

新生代老年代不再从物理上进行隔离,把内存划分成若干个大小相等的区域/

运行步骤:

1.初始标记

2.并发标记

3.最终标记

4.筛选回收

新老收集器的组合:

serial和ParNew可以和CMS与Serial Old进行组合

Parallel Scavenge可以与Serial Parallel Old进行组合

G1独成一派.


现在再来看上面的三个问题

1.哪些内存需要回收?

不存活的对象需要被回收,即不能被任何途径所引用的对象.

2.什么时候对其进行回收?

参考上边GC的情况,什么时候会触发MInorGc 什么时候会触发FullGC.

3.怎么进行回收操作.?

通过收集器进行GC.

再细节的东西 对于我来说还无能为力,我只能分享现在已知的,下边看一下GC日志怎么看

GC日志查看

[Full GC (System.gc()) [Tenured: 0K->593K(10944K), 0.0030196 secs] 1265K->593K(15872K), [Metaspace: 209K->209K(4480K)], 0.0030870 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

FULL GC:代表触发了Stop the World 也是GC的类型

Tenured:代表年老代

0.0030196 secs:为用时

0K->593K(10944K):空间变动,括号内为总空间

MetaSpace:为元空间,这里编译器采用的JDK版本为1.8,永久带被移除方法区, GC针对老年代和新生代,不用太过关注.

from Space与To space :就是之前两块survivor空间.

GC信息可以通过在idea中的Edit configuration->vm options处加入-XX:+PrintGCDetails后.

通过System.gc进行输出.

下边是GC的一些设置参数:

堆设置
-Xms :初始堆大小
-Xmx :最大堆大小
-XX:NewSize=n :设置年轻代大小
-XX:NewRatio=n: 设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n :年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n :设置持久代大小

收集器设置
-XX:+UseSerialGC :设置串行收集器
-XX:+UseParallelGC :设置并行收集器
-XX:+UseParalledlOldGC :设置并行年老代收集器
-XX:+UseConcMarkSweepGC :设置并发收集器

垃圾回收统计信息
-XX:+PrintHeapAtGC GC的heap详情
-XX:+PrintGCDetails GC详情
-XX:+PrintGCTimeStamps 打印GC时间信息
-XX:+PrintTenuringDistribution 打印年龄信息等
-XX:+HandlePromotionFailure 老年代分配担保(true or false)

并行收集器设置
-XX:ParallelGCThreads=n :设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n :设置并行收集最大暂停时间
-XX:GCTimeRatio=n :设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

并发收集器设置
-XX:+CMSIncrementalMode :设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n :设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数

Reference:

1.https://blog.csdn.net/bear_lam/article/details/79648701
2.http://www.importnew.com/15820.html
3.https://blog.csdn.net/huzhigenlaohu/article/details/51918854
4.深入理解JVA虚拟机 第二版 P61-P100

posted @ 2018-05-16 16:38  CurryRice  阅读(391)  评论(0编辑  收藏  举报