转自:http://blog.takipi.com/garbage-collectors-serial-vs-parallel-vs-cms-vs-the-g1-and-whats-new-in-java-8/?utm_source=blog&utm_medium=in-post&utm_content=gcmisconceptions&utm_campaign=java

The 4 Java Garbage Collectors – How the Wrong Choice Dramatically Impacts Performance

The year is 2014 and there are two things that still remain a mystery to most developers – Garbage collection and understanding the opposite sex. Since I don’t know much about the latter, I thought I’d take a whack at the former, especially as this is an area that has seen some major changes and improvements with Java 8, especially with the removal of the PermGen and some new and exciting optimizations (more on this towards the end).

When we speak about garbage collection, the vast majority of us know the concept and employ it in our everyday programming. Even so, there’s much about it we don’t understand, and that’s when things get painful. One of the biggest misconceptions about the JVM is that it has one garbage collector, where in fact it provides four different ones, each with its own unique advantages and disadvantages. The choice of which one to use isn’t automatic and lies on your shoulders and the differences in throughput and application pauses can be dramatic.

What’s common about these four garbage collection algorithms is that they are generational(分代的), which means they split the managed heap into different segments(将堆分为几个部分来管理), using the age-old assumptions that most objects in the heap are short lived and should be recycled quickly(一般而言我们假定堆上的大部分对象的生命周期是很短的,应该很快被回收,所以采用分代的回收算法). As this too is a well-covered area, I’m going to jump directly into the different algorithms, along with their pros and their cons.

1. The Serial Collector

The serial collector is the simplest one, and the one you probably won’t be using, as it’s mainly designed for single-threaded environments (e.g. 32 bit or Windows) and for small heaps. This collector freezes all application threads whenever it’s working, which disqualifies it for all intents and purposes from being used in a server environment(不会在有低延时要求和服务器环境使用).(因此可以忽略该垃圾收集算法)

How to use it: You can use it by turning on the -XX:+UseSerialGC JVM argument,

2. The Parallel / Throughput collector

Next off is the Parallel collector. This is the JVM’s default collector. Much like its name, its biggest advantage is that is uses multiple threads to scan through and compact the heap. The downside to the parallel collector is that it will stop application threads when performing either a minor or full GC collection. The parallel collector is best suited for apps that can tolerate application pauses and are trying to optimize for lower CPU overhead caused by the collector.

3. The CMS Collector

Following up on the parallel collector is the CMS collector (“concurrent-mark-sweep”). This algorithm uses multiple threads (“concurrent”) to scan through the heap (“mark”) for unused objects that can be recycled (“sweep”). This algorithm will enter “stop the world” (STW) mode in two cases: when initializing the initial marking of roots (objects in the old generation that are reachable from thread entry points or static variables) and when the application has changed the state of the heap while the algorithm was running concurrently, forcing it to go back and do some final touches to make sure it has the right objects marked.

The biggest concern when using this collector is encountering promotion failures which are instances where a race condition occurs between collecting the young and old generations. If the collector needs to promote young objects to the old generation, but hasn’t had enough time to make space clear it,  it will have to do so first which will result in a full STW collection – the very thing this CMS collector was meant to prevent. To make sure this doesn’t happen you would either increase the size of the old generation (or the entire heap for that matter) or allocate more background threads to the collector for him to compete with the rate of object allocation.

Another downside to this algorithm in comparison to the parallel collector is that it uses more CPU in order to provide the application with higher levels of continuous throughput, by using multiple threads to perform scanning and collection. For most long-running server applications which are adverse to application freezes, that’s usually a good trade off to make. Even so, this algorithm is not on by default. You have to specify XX:+USeParNewGC to actually enable it. If you’re willing to allocate more CPU resources to avoid application pauses this is the collector you’ll probably want to use, assuming that your heap is less than 4Gb in size.  However, if it’s greater than 4GB, you’ll probably want to use the last algorithm – the G1 Collector.

4. The G1 Collector

The Garbage first collector (G1) introduced in JDK 7 update 4 was designed to better support heaps larger than 4GB. The G1 collector utilizes multiple background threads to scan through the heap that it divides into regions, spanning from 1MB to 32MB (depending on the size of your heap). G1 collector is geared towards scanning those regions that contain the most garbage objects first, giving it its name (Garbage first). This collector is turned on using the –XX:+UseG1GC flag.

This strategy the chance of the heap being depleted before background threads have finished scanning for unused objects, in which case the collector will have to stop the application which will result in a STW collection(直到堆内存被耗尽才会停止扫描未被使用的对象,开始回收,这会导致STW的后果). The G1 also has another advantage that is that it compacts the heap on-the-go, something the CMS collector only does during full STW collections(G1算法有一个优势,它可以不妨碍堆内存分配的同时整理堆内存,防止堆内存碎片化,而CMS只有在STW时才会整理堆内存).

Large heaps have been a fairly contentious area over the past few years with many developers moving away from the single JVM per machine model to more micro-service, componentized architectures with multiple JVMs per machine. This has been driven by many factors including the desire to isolate different application parts, simplifying deployment and avoiding the cost which would usually come with reloading application classes into memory (something which has actually been improved in Java 8).(大堆内存的采用目前有很大争议,许多开发者倾斜于采用微服务,组件化的架构——一台服务器运行多个jvm,这样可以将应用进行隔离,简化部署)

Even so, one of the biggest drivers to do this when it comes to the JVM stems from the desire to avoid those long “stop the world” pauses (which can take many seconds in a large collection) that occur with large heaps. This has also been accelerated by container technologies like Docker that enable you to deploy multiple apps on the same physical machine with relative ease.

Java 8 and the G1 Collector

Another beautiful optimization which was just out with Java 8 update 20 for is the G1 Collector String deduplication. Since strings (and their internal char[] arrays) takes much of our heap, a new optimization has been made that enables the G1 collector to identify strings which are duplicated more than once across your heap and correct them to point into the same internal char[] array, to avoid multiple copies of the same string from residing inefficiently within the heap. You can use the -XX:+UseStringDeduplicationJVM argument to try this out.

Java 8 and PermGen

One of the biggest changes made in Java 8 was removing the permgen part of the heap that was traditionally allocated for class meta-data, interned strings and static variables. This would traditionally require developers with applications that would load significant amount of classes (something common with apps using enterprise containers) to optimize and tune for this portion of the heap specifically. This has over the years become the source of many OutOfMemory exceptions, so having the JVM (mostly) take care if it is a very nice addition. Even so, that in itself will probably not reduce the tide of developers decoupling their apps into multiple JVMs.

Each of these collectors is configured and tuned differently with a slew of toggles and switches, each with the potential to increase or decrease throughput, all based on the specific behavior of your app. We’ll delve into the key strategies of configuring each of these in our next posts.

In the meanwhile, what are the things you’re most interested in learning about regarding the differences between the different collectors? Hit me up in the comments section

Additional reading –

1. A really great in-depth review of the G1 Collector on InfoQ.

2. Java performance – The definitive guide. My favorite book on Java performance.

3. More about String deduplication on the CodeCentric blog.

----------------------------------------

自己的总结

1)Parallel CMS ,G1都是使用多个线程在后台扫描垃圾(Serial 可以忽略掉);

2)Parallel 缺点是无论minor gc还是full gc都会暂停应用(所以应用不能容忍较多延时暂停的不要采用),优点是消耗CPU低;是默认的;

3)CMS优点是暂停应用的次数(频率)较少,缺点是会消耗较多的CPU,堆内存碎片化;采用CMS时应该分配大的堆内存(老年代)和多的后台收集线程来减少STW的发生;

4)G1优点是减少了暂停应用的次数(频率),却增加了每次暂停应用的时长;没有堆内存碎片化的缺点;

5)堆内存的永久区去掉了,因为以前该区会导致很多内存溢出,去掉之后又jvm自己接管,我们无法指定大小了;

感觉还是CMS比较靠谱些,其次是G1,最后才是Parallel,至于Serial 可以忽略掉。当然还是要看应用的实际运行情况来进行选择。

Garbage Collectors – Serial vs. Parallel vs. CMS vs. G1 (and what’s new in Java 8)的更多相关文章

  1. Garbage Collectors - Serial vs. Parallel vs. CMS vs. G1 (and what's new in Java 8)--转

    The 4 Java Garbage Collectors - How the Wrong Choice Dramatically Impacts Performance The year is 20 ...

  2. Java垃圾收集器——Serial,Parallel,CMS,G1收集器概述

    1.概述 Java应用启动的时候,除了配置Xms以及Xmx参数(Xmx:InitialHeapSize, Xms:MaxHeapSize),还需要选择合适的垃圾收集器. 截止Jdk1.8,共提供了7款 ...

  3. 垃圾收集器Serial 、Parallel、CMS、G1

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt378 这里介绍4个垃圾收集器,如果进行了错误的选择将会大大的影响程序的性能. ...

  4. JVM七大垃圾回收器上篇Serial、ParNeW、Parallel Scavenge、 Serial Old、 Parallel Old、 CMS、 G1

    GC逻辑分类 垃圾收集器没有在规范中进行过多的规定,可以由不同的厂商.不同版本的JVM来实现. 由于JDK的版本处于高速迭代过程中,因此Java发展至今已经衍生了众多的GC版本. 从不同角度分析垃圾收 ...

  5. Java Garbage Collectors

    Generational Collectors (分代收集器) GC algos optimised based on two hypotheses / observations: Most obje ...

  6. 细述 Java垃圾回收机制→Types of Java Garbage Collectors

    细述 Java垃圾回收机制→Types of Java Garbage Collectors 转自:https://segmentfault.com/a/1190000006214497 本文非原创, ...

  7. Serial 与 Parallel GC 之间的不同之处?

    Serial 与 Parallel 在 GC 执行的时候都会引起 stop-the-world.它们之间主要 不同 serial 收集器是默认的复制收集器,执行 GC 的时候只有一个线程,而 para ...

  8. java垃圾回收及gc全面解析(全面覆盖cms、g1、zgc、openj9)

    一般来说,gc的停顿时间和活跃对象的堆大小成比例,视gc线程的数量,每1GB可能会停顿1-3秒,且cpu数量通常和gc呈现阿姆达尔定律(Amdahl’s Law),而非我们直观计算的线性变化.如下: ...

  9. jvm回收器回收过程一:CMS和 G1的初认知(持续更新中)

    CMS:介绍: 1.CMS(Concurrent Mark-Sweep)是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器.对于要求服务器响应速度的应用上,这种垃圾回收器非常适合. 在启动JVM参 ...

随机推荐

  1. 使用WinDbg调试SQL Server——入门

    这篇文章我想探究下SQL Server里完全不同的领域:如果使用WinDbg(来自针对Windows的调试工具)调试SQL Server.在我们进入枯涩细节之前,我想详细解释下为什么选择这样晦涩的话题 ...

  2. 浅谈DOM性能考虑

    浅谈DOM性能考虑 很多人都会忽视脚本对Web应用整体性能的影响.为保证应用的流畅运行,在为文档编写和应用脚本时,需要注意一些问题.一.尽量减少访问DOM和尽量减少标记    访问DOM的方式对脚本性 ...

  3. Java魔法堂:注解用法详解——@SuppressWarnings

    一.前言 编码时我们总会发现如下变量未被使用的警告提示: 上述代码编译通过且可以运行,但每行前面的“感叹号”就严重阻碍了我们判断该行是否设置的断点了.这时我们可以在方法前添加 @SuppressWar ...

  4. BZOJ1015 并查集

    1015: [JSOI2008]星球大战star war Description 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了 ...

  5. web面试题大全

    $HTML, HTTP,web综合问题 常见排序算法的时间复杂度,空间复杂度 前端需要注意哪些SEO web开发中会话跟踪的方法有哪些 <img>的title和alt有什么区别 docty ...

  6. C#类的一些概念

    一.概念 1.类的作用是来模拟现实对象的,一个现实对象可以从两个地方进行描述:特征和行为. 2.类不是你凭空想象的,它只是描述现实对象具体的特征和行为的. 3我们写类只需要写我们所需要的. 4.类是提 ...

  7. C#反射的应用

    项目框架中有一个很实用的方法,它用来获取客户端post的数据,并自动赋值到对象各属性,这样后台少写了很多代码.但是对于有主表.子表的表单,框架中没有提供自动给子表对象各属性赋值的方法,每次都要写很多代 ...

  8. 【Unity】13.2 通过Lighting Window设置相关参数

    分类:Unity.C#.VS2015 创建日期:2016-05-19 一.简介 Unity 5.3.4的Lighting Window有3个选项卡:Object.Scene.Lightmaps. 二. ...

  9. 使用栈Stack对整数数值的运算表达式字符串进行运算C#

    这里如果对于形如字符串“((6+((7+8)-9)*9+8/2)-3)/2”的运算表达式进行运算.接触过此类的同学知道这种存在着运算符优先级的表达式,不能直接从左到右进行运算,我们使用OperandS ...

  10. DoTween小结

    using UnityEngine; using System.Collections; using DG.Tweening; public class GetStart : MonoBehaviou ...