图片 1

JVM垃圾回收(二)

1. 只有一个垃圾回收器

不,并且4也是错误的答案。HotSpot JVM一共有4个垃圾回收器:Serial,
Parallel / Throughput. CMS, and the new kid on the block
G1。别急,另外还有一些非标准的垃圾回收器和更大胆的实现,比如Shenandoah或
者其他JVM使用的回收器(C4——Azul开发的无停顿回收器)。HotSpot默认使用Parallel
/
Throughput回收器,但它常常不是你运行程序的最佳选择。比如CMS和G1会使GC停顿(GC
pause)发生的频率降低,但是对于每次停顿所花费的时间,很可能比Parallel回收器更长。另一方面来说,在使用相同大小堆内存的情况下,Parallel回收器能带来更高的吞吐量。

结论:根据你的需求(可接受的GC停顿频率和持续时间)选择合适的垃圾回收器。

在CPU数目较少的情况下,会造成程序响应很慢。

总结

希望上面的结论能帮助你们更好地把握Java垃圾回收器的工作。在你们的程序中出现过类似问题吗?你们周围还有没有其他对GC常见的误解?请在下面的评论区留言。

空间整合。G1收集器采用“标记-整理”算法,不会产生大量的内存空间碎片。


我还是小孩的时候,父母常说如果你不好好学习,就只能去扫大街了。但他们不知道的是,清理垃圾实际上是很棒的一件事。可能这也是即使在Java的世界中,
同样有很多开发者对GC算法产生误解的原因——包括它们怎样工作、GC是如何影响程序运行和你能对它做些什么。因此我们找到了Java性能调优专家Haim
Yadid,并把名为Java performance tuning
guide的文章发表在Takipi的博客上。

单线程的收集器。在进行垃圾回收时,必须停止所有的用户线程并一直到清理完毕,对应老年代的版本为Serial
Old。

对Java垃圾回收最大的误解是什么?它实际又是什么样的呢?

另外一个缺点就是清理算法本身的缺陷。前面提到过对于Mark-Sweep算法,容易造成大量不连续的内存碎片。在分配大对象时,如果找不到足够大的连续空间,则会触发Full
GC。

5. 降低新对象的分配率可以改善GC的运行状况

我们可以
粗略地把系统中的对象分为三种:长命(long-lived)对象,对它们我们一般做不了什么;中等寿命(mid-lived)对象,最大的问题可能出现在这;短命(short-lived)对象,它们的释放和回收通常都很快,在下个GC周期来临时就会消失。专注于中等寿命对象的分配率可以带来有益的结
果,这对短命和长命的对象却不是那么有效。另外,控制中等寿命对象往往是一项困难的工作。

结论:给服务器带来压力的并不单纯是对象的分配率,在运行过程中这些对象的种类才是一切麻烦的根源。

Parallel: 并行的,代表垃圾回收占用多个线程。

带着对性能调优指南浓厚的兴趣,我们决定在这篇后续的博文中收集一些关于垃圾回收的流行观点,并且指出为什么它们完全是错误的。

Parallel
Old收集器

4. 平均事务时间是最需要被关注的指标


果你仅仅监控服务器的平均事务时间,那么很可能错过一些异常值。这些异常的情况可能对用户来说是毁灭性的,而人们没有意识到它的重要性。比如一个事务在正常情况下耗时100ms,但受到GC停顿的影响,花了1分钟才完成。除了用户没人会注意到这个问题,因为你只观察了平均事务时间。试想有1%或者更多的用
户经历了这个场景,如果只关注平均值,它就太容易被忽略了。想了解更多和延迟相关的问题和怎样正确处理,可以在这里阅读Gil
Tene的博客。

结论:留心那些异常值,你可以知道系统最后那1%的状况。(可不是这个1%)

G1收集器

6. 调优可以解决所有事

如果你的程序需要保存大量被频繁修改的状态,对JVM堆内存进行调优就无法带来很好的收益。较长的GC停顿是不可避免的。一个解决办
法是对架构进行改善,保证一个对响应时间有决定性影响或者造成瓶颈的过程中,不包含大量状态。大量状态和响应能力是难以良好共存的,因此将它们分开处理才
是上上之选。

结论:不是所有的问题都可以通过调整JVM参数解决,有时你只需要回顾自己的绘图板。(译注:重新审视程序的设计)

-XX:GCTimeRatio指定垃圾回收所占的时间比。

最新博文:关于垃圾回收被误解的7件事
pic.twitter.com/aqQEF0zTkK
— Takipi (@takipid) April 6, 2015

【嵌牛导读】:本篇接着上一篇 JVM垃圾回收(一)进行阐述

2. 并行(Parallel) = 并发(Concurrent)

一个GC周期(Garbage Collection
cycle)可以以STW(Stop-The-World)的形式出现,这会发生一次GC停顿,也可以并发地执行从而无需暂停应用程序。更进一步来
讲,GC算法本身可以是串行的(单线程),也可以是并行的(多线程)。因此当我们提到并发的GC时,并不代表它是并行完成的,相反当提到串行GC时,也并
不意味着就一定会出现GC停顿。在GC的世界中,并发和并行是两个完全不同的概念。并发针对的是GC周期,而并行针对GC算法自身。

结论:垃圾回收的过程实际上有两步,启动GC周期和GC自身运行,这是不同的两件事。

这里先介绍几个单词的意思:

3. G1能解决所有问题

经过一系列修正和改 进,Java
7中引入了G1回收器,它是JVM垃圾回收器中最新的组件。G1最大的优势就是解决了CMS中常见的内存碎片问题:GC周期会从老年代(Old
Generation)中释放内存块,结果内存变得像瑞士奶酪那样千疮百孔,直到JVM对其无从下手了,才不得不停下来处理这些碎片。但是故事没这么简
单,某些情况下其他回收器可能比G1有更好的表现,这完全取决于你的需求。

结论:没有一个奇迹般的回收器能解决所有GC问题,你应该通过具体实验来选择合适的回收器。

为Serial收集器的老年代版本。一是用于和Parallel
Scavenge收集器联合使用,而是作为当CMS发生Concurrent Mode
Failure的备选方案。

来看看前7名:

Parallel
Scavenge收集器

7. GC日志会导致巨大的系统开销

简单来说,这是错的,尤
其在默认的日志配置下。日志数据是极为有价值的,Java
7中还引入了钩子来控制它们的大小,保证硬盘空间不被用尽。如果不收集GC日志,那么你会失去这几乎是唯一的,知晓JVM垃圾回收器在生产环境中工作状态
的方法。一般可接受的GC开销以5%作为上限,如果你能知道系统为GC停顿付出的代价,也能对最小化这个代价采取行动,这种程度的开销是不值一提的。

结论:在能力范围内,尽可能多地获取系统在生产环境中的运行数据,你会发现那是一个全新的世界。

CMS(Concurrent Mark
Sweep)收集器以降低停顿时间为目标,主要用在用户交互的程序当中。采用的是“标记-清理”算法来对老年代进行垃圾回收。其收集过程分成四个部分:

Serial
Old收集器

ParNew收集器

CMS收集器

垃圾回收器

分代收集。G1收集器能够管理整个GC堆,看上面的图就知道其横跨了新老两代。

初始标记,需要停止所有的用户线程。仅标记一下GC
Roots关联到的对象,速度比较快。

也是一个多线程收集器,采取复制算法对新生代进行垃圾回收。

并发清除。正式进行清除。

参考:www.stephenzhang.me

Serial收集器

在单CPU的环境中简单且高效,没有多线程交互带来的开销。

Parallel Scavenge收集器主要采取两个参数进行调优:

-XX:MaxGCPauseMills指定每次停顿的时长,并不是越短越好,停顿的时间越短,越利于和用户交互的程序,但是会牺牲吞吐量。

为了避免可达性分析时进行全堆扫描,G1收集器为每个Region维护了一个Remembered
Set。当对Reference类型的数据进行写入时,先产生一个Write
Barrier暂停写操作,如果引用的对象处在不同的Region,则把引用信息记录到此Region的Remembered
Set当中,这样就避免了对整个堆进行扫描。

参考:《深入理解Java虚拟机》

主要是和CMS收集器联合使用,由上图可以看出,只有Serial和ParNew收集器可以和CMS联用。

并发处理。与CMS相同,能够让清理线程和用户线程一同运行。

之所以能够建立可预测的停顿时间模型,是因为G1收集器记录各个Region的垃圾堆积的价值大小(内存大小和收集所需要的时间),并在后台维护一个优先级列表,每次回收时根据优先级队列,在有限时间内收集价值最大的Region,这也是收集器的名字由来(Garbage
First)。

姓名:屈哲西                       学号:15130130272

可预测的停顿。建立了一个可以预测的停顿时间模型。

用直线相连的代表可以配合使用。

其主要的目标是实现大的吞吐量。参照之前的关于操作系统调度算法的文章。吞吐量(Throughput)的计算公式为:吞吐量
= 用户代码运行时间 / (用户代码运行时间 + 垃圾收集时间)。

重新标记,需要停止所有的用户线程。修正并发标记阶段引用关系发生改动的对象。

如果在并发清理的阶段有垃圾产生的话,那么这些垃圾不会在此并发清除阶段回收,这些垃圾称为“浮动垃圾”。因为清除阶段会和用户线程一同运行,所以不能等到老年代被填满后才开始垃圾回收。要是CMS预留的内存无法满足需求的话,会产生”Concurrent
Mode Failure”,此时JVM会采用Serial Old备选方案。

CMS收集器做到了用户线程和垃圾收集线程同时运行,具有划时代意义,但仍然存在一些显著的缺点:

【嵌牛正文】:

Serial收集器的多线程版本,同样也需要停止所有的用户线程。其回收策略与Serial基本一模一样。

【嵌牛鼻子】:JAVA虚拟机,JVM

图片 1

Concurrent: 并发的,指垃圾回收线程和用户线程同时运行。

并发标记。是一个跟踪的过程,找出存活的对象。时间较慢。

下面来看一下几种常见的垃圾收集器,大致如图所示:

【嵌牛提问】:JVM为什么要垃圾回收

除了上述两个参数之外,还有一个称为-XX:+UseAdaptiveSizePolicy的参数,此参数用于虚拟机根据上面两个参数进行自动调优,这样就不用显式指定-Xmn,
-XX:SurvivorRatio等参数。

Serial: 串行的,代表垃圾回收只占用一个线程。

用于和Parallel Scavenge收集器联合使用,主要用在注重吞吐量的场合。

Sun公司赋予G1收集器的使命是替代掉之前的CMS收集器,作为面向服务端应用的主要垃圾回收器。该垃圾回收器有如下特点:

在单CPU的环境当中,存在多线程交互的开销,其性能不会比Serial收集器表现地好。

发表评论

电子邮件地址不会被公开。 必填项已用*标注