JVM内存模型及垃圾回收的研究总结

小说:高羊茅种子哪里卖?作者:帝董安成更新时间:2019-04-19字数:80351

 Java内存模型

总的来说就分为两个区域,堆内存(Heap)和非堆内存(No-Heap),非堆内存又称为永久代(Permanent),“永久”其实有点儿容易使人误导,好像这部分内容不需要回收。但在永久区中的某些数据也是需要回收的!

在新的JDK8中,这部分的名称已经不叫Permanent了,改成更好理解的Metaspace了。这部分是用来存储JVM工作的相关数据的,比如Load下来的class定义、静态变量、用于调度的方法和线程栈。

 

分为两个区其实是为了更便于理解,No-Heap区只是非Heap的意思,其中的Stack、Method Area其实是和Heap同级的。

在GC日志中,你会发现PSPermGen也在其中:

[GC-- [PSYoungGen: 569856K->569856K(617472K)] 773089K->928306K(976896K), 0.3285123 secs] [Times: user=0.66 sys=0.08, real=0.33 secs] 
[Full GC [PSYoungGen: 569856K->0K(617472K)] [ParOldGen: 358450K->359349K(499712K)] 928306K->359349K(1117184K) [PSPermGen: 64652K->64650K(131072K)], 1.4693823 secs] [Times: user=4.09 sys=0.02, real=1.47 secs] 
[Full GC [PSYoungGen: 569856K->0K(617472K)] [ParOldGen: 359349K->488638K(672768K)] 929205K->488638K(1290240K) [PSPermGen: 65041K->65041K(131072K)], 2.4092196 secs] [Times: user=6.75 sys=0.11, real=2.41 secs] 

 

意思是No-Heap(永久代)也需要垃圾回收!

因为在永久代中还存储着ClassLoader、Class的元信息(Metadata)、指向Heap区域对象的指针以及字符串池(Internal String)。这些数据其实也需要垃圾回收。

这样看来,把内存区域划分为年轻代(Young Gen)、老年代(Old Gen)和永久代(Permanent Gen)其实是有道理的,虽然老年代的数据不会提升到永久代中。但是这三个区域的数据都是需要垃圾回收的。

 

Heap(堆内存)

堆内存是垃圾回收器工作的地方,堆内存又分为Eden和两个大小一样的Survivor区,即From和To。

最开始的对象都会存储在Eden中(如果有些大对象无法存入到年轻代,则会直接存入老年代),然后经过Minor GC之后会被提升到Survivor区,然后再提升到老年代。

 

 

 Stack(栈内存)

Thread Stack 用来存放栈信息,每个线程栈信息里各自有自己的方法栈(包括本地方法栈),在方法栈的每一帧里存储着方法调用的相关信息,比如参数值、局部变量、返回值等。

Program Counter:记录着当前语句执行到哪儿了。

下图中,其实Stack可以归并到No-Heap中。

 

 

垃圾回关注的指标

吞吐量

定义:用户代码执行时间  / ( 用户代码执行时间 + 垃圾回收时间)

越高越好,越高表示执行垃圾回收时间越少。

暂停时间

回收时可能需要暂停用户线程,暂停时间越短越好。

执行频率

单位时间垃圾回收执行的次数。

堆内存大小

比如G1回收器就要去比较大的Heap内存。

敏感度(Promptness)

对象变成垃圾到被回收的时间,时间越短表示回收器越敏感。

 

 

垃圾回收类型

串行搜集器(Serial)

年轻代(Young Gen)回收

 

老年代(Old Gen)回收

 来年代的回收很简单,步骤是“标记-清除-压缩”:

串行回收器的使用场景

一般引用于不要求“低暂停”的client模式。这里参考server和client的区别。j2se5的client模式下默认使用串行回收器进行垃圾回收。

使用串行回收器的参数:-XX:+UseSerialGC

 

并行回收器(Paraller)

并行回收器可以利用多个CPU进行并行的垃圾回收。(在多个CPU场景下,使用Serial回收器时,其实只有一个CPU在工作,其他CPU相当于闲置状态)

并行回收器在年轻地啊和老年代进行垃圾回收的操作是一样的,都是标记、转移、压缩,只是它启用了多个CPU并发执行。串行和并行都需要stop-the-world。

并行回收器的使用场景

 应用于多CPU场景下,但是没有太大的暂停时间要求,因为还是有可能会发生长时间的老年代垃圾回收。

适用于批处理、账单、财务、科学计算等场景。

j2se5的server模式下默认使用该回收器。

使用并行回收器的参数:-XX:+UseParallelGC

 ParNew

这是一个加强版的Parallel回收器。它可以与下面提到的CMS回收器进行配合。

 

并行压缩回收器(Parallel Compacting)

 年轻代使用并行回收器一样的算法(多CPU并行回收)。(stop-the-world)

-XX:+UseParallelOldGC.

 对于老年代,回收过程分为三个阶段

并行标记(Marking)

标记出每个区域的活动数据。标记动作其实是和用户线程一起跑的。

计算总结(Summary)

计算各个区域的稠密程度,得出移动数据的方案。(稀疏的往稠密位置移动,压缩速度肯定比相反方向要快)

压缩(Compaction)

把数据移动到一端,保证另外一端空白。

并行压缩回收器的使用场景

多CPU,它相对于并行回收器感觉没有什么区别(谁知道吗???),因为在官方文档中是这样说的:

使用该回收器的参数:-XX:-UseParallelOldGC

 

并发标记清理回收器(Concurrent Mark-Sweep (CMS))

低延迟的回收器。

一般而言,年轻代的回收不会有太大的暂停。而老年代的回收不会经常执行,所以老年代的回收暂停时间长一点儿也没事。CMS的回收步骤如下:

年轻代还是使用并发回收器(Parallel)。

对于老年代:

初始标记(init mark):单线程stop-the-world执行,短暂停,确定出直接和程序关联的活动对象集合。

并发标记(concurrent marking):根据上一步标记出来的集合,并发找出与集合中元素关联的其他活动对象。这一步的执行是和用户线程并发执行的。

重新标记(remark):由于用户线程也在运行,所以上一步标记出来的对象还有可能又参数了垃圾,所以这里再次stop-the-world,重新找出活动数据。这一步对现场并发执行。很容易理解,这里的stop-the-world也是非常短的。

清理(sweep):根据上一步标记结果,清理内存。

 

 

 从CMS的执行步骤可以看出,它的核心思想其实就是把事情分成多个步骤来做,不要一次把事情做完,且尽量和用户线程一起执行,从而实现对用户线程的低延迟。

 

CMS回收器使用场景

任何需要低延迟的应用。甚至在单CPU上都运行良好。

使用CMS回收器参数:-XX:+UseConcMarkSweepGC

 

G1(Gargage First)回收器

G1回收器是用于server模式下,多处理器、大内存的环境。其目标是高吞吐量、高可用性。在JDK7 update4以后的版本中都支持。长期计划中G1是用来代替CMS回收器的。

G1不像其他回收器那样,把内存明确地划分为三个固定大小的区域。而是把heap看成一个整体。

更多细节详见参考连接。

 

垃圾收集器参数总结

收集器设置:

-XX:+UseSerialGC:年轻串行(Serial),老年串行(Serial Old)

-XX:+UseParNewGC:年轻并行(ParNew),老年串行(Serial Old)

-XX:+UseConcMarkSweepGC:年轻并行(ParNew),老年串行(CMS),备份(Serial Old)

-XX:+UseParallelGC:年轻并行吞吐(Parallel Scavenge),老年串行(Serial Old)

-XX:+UseParalledlOldGC:年轻并行吞吐(Parallel Scavenge),老年并行吞吐(Parallel Old)

 

收集器参数:

 -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。

-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间

-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。

-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。

 

 个人学习总结,难免有误,欢迎指正讨论!


 

参考:

Java堆内存:http://www.blogjava.net/fancydeepin/archive/2013/09/29/jvm_heep.html

官方文档,介绍内存回收原理:http://www.oracle.com/technetwork/java/javase/tech/memorymanagement-whitepaper-1-150020.pdf

JVM内部结构:http://blog.jamesdbloom.com/JVMInternals.html

JVM参数:http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html,http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html

官网介绍GC日志:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html

G1回收器:http://www.oracle.com/technetwork/tutorials/tutorials-1876574.html

 

当前文章:http://www.leetaemin.cn/content/09-16/32420/content_9958389640.html

发布时间:2019-04-19 02:43:06

浙江黄金柳价格便宜吗? 八角金盘小苗的价格 哪里有卖李叶绣线菊? 【行情快报】最新红叶碧桃价格,来自中国最大观赏桃产区报价表 哪里绣球花最多? 国槐种植育苗——技术指南(上) 目前构树的行情怎么样 专家说来含苞待放的玫瑰花比开放之后更有价值哦 北方可以种地棠花吗 高度150公分的红枫小苗多少钱一株?

43087 37172 20769 28053 39704 63289 47405 78634 33605 92125 63111 85595 63884 42426 59334 57399 55792 44453 31544 59641 58307 61239 61733

我要说两句: (0人参与)

发布