Garbage Collectors – Serial vs. Parallel vs. CMS vs. G1 (and what’s new in Java 8)

转自: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比较靠谱些。当然还是要看实际运行情况。

时间: 2024-10-07 06:09:40

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

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 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

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

详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt378 这里介绍4个垃圾收集器,如果进行了错误的选择将会大大的影响程序的性能. 时至今日,仍然有两个事情困扰着开发人员:垃圾收集(GC)和了解异性(程序猿的悲鸣),后者我确实不太了解,因为我被前者搞的无暇顾及怎么了解异性,特别是当知道在JAVA8中对这一区域有了很大的改进和提升还有移除了PermGen和以一些新的令人兴奋的调优. 当我们谈到垃圾回收时,我们绝大多数都知道利用它

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

细述 Java垃圾回收机制→Types of Java Garbage Collectors 转自:https://segmentfault.com/a/1190000006214497 本文非原创,翻译自Types of Java Garbage Collectors在Java中为对象分配和释放内存空间都是由垃圾回收线程自动执行完成的.和C语言不一样的是Java程序员不需要手动写垃圾回收相关的代码.这是使得Java如此流行,同时也是Java能帮助程序员写出更好的Java应用的优点之一. 本文将

Oracle JVM Garbage Collectors Available From JDK 1.7.0_04 And After

Jack Shirazi tells you what garbage collectors and garbage collector combinations are available from the Oracle Java 7 update 4 JVM and onwards, including Java 8 and Java 9. Published June 2012, Updated September 2015, Author Jack Shirazi --From http

弄明白CMS和G1,就靠这一篇了

目录 1 CMS收集器 安全点(Safepoint) 安全区域 2 G1收集器 卡表(Card Table) 3 总结 4 参考 在开始介绍CMS和G1前,我们可以剧透几点: 根据不同分代的特点,收集器可能不同.有些收集器可以同时用于新生代和老年代,而有些时候,则需要分别为新生代或老年代选用合适的收集器.一般来说,新生代收集器的收集频率较高,应选用性能高效的收集器:而老年代收集器收集次数相对较少,对空间较为敏感,应当避免选择基于复制算法的收集器. 在垃圾收集执行的时刻,应用程序需要暂停运行. 可

JVM垃圾收集器CMS和G1

CMS(Concurrent Mark Sweep)收集器是一种以获取 最短回收停顿时间 为目标的收集器.采用的是"标记-清除算法",整个过程分为4步 由于整个过程中,并发标记和并发清除,收集器线程可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行的.集器 G1特点: (1)初始标记 CMS initial mark 标记GC Roots能关联到的对象 Stop The World--->速度很快 (2)并发标记 CMS concurre

垃圾收集器(Garbage Collectors)

Java中垃圾回收有什么目的?什么时候进行垃圾回收? 垃圾回收的目的是识别并且丢弃应用不再使用的对象来释放和重用资源. System.gc()和Runtime.gc()会做什么事情? 这两个方法用来提示JVM要进行垃圾回收.但是,立即开始还是延迟进行垃圾回收是取决于JVM的. finalize()方法什么时候被调用?析构函数(finalization)的目的是什么? 在释放对象占用的内存之前,垃圾收集器会调用对象的finalize()方法.一般建议在该方法中释放对象持有的资源. 如果对象的引用被

CMS和G1的区别

CMS:以获取最短回收停顿时间为目标的收集器,基于并发"标记清理"实现 过程: 1.初始标记:独占PUC,仅标记GCroots能直接关联的对象 2.并发标记:可以和用户线程并行执行,标记所有可达对象 3.重新标记:独占CPU(STW),对并发标记阶段用户线程运行产生的垃圾对象进行标记修正 4.并发清理:可以和用户线程并行执行,清理垃圾 优点: 并发,低停顿 缺点: 1.对CPU非常敏感:在并发阶段虽然不会导致用户线程停顿,但是会因为占用了一部分线程使应用程序变慢 2.无法处理浮动垃圾:

G1垃圾收集器和CMS垃圾收集器 (http://mm.fancymore.com/reading/G1-CMS%E5%9E%83%E5%9C%BE%E7%AE%97%E6%B3%95.html#toc_8)

参考来源 JVM 体系架构 堆/栈的内存分配 静态和非静态方法的内存分配 CMS 回收算法 应用场景 CMS 垃圾收集阶段划分(Collection Phases) CMS什么时候启动 CMS缺点 G1收集算法 G1的发展 分代垃圾回收瓶颈 G1使用场景 G1特点 G1堆内存的分配 G1的进程内存占用(Footprint) G1 收集器收集过程 G1命令行参数 记录G1的GC日志 G1性能调优 参考来源 http://blog.csdn.net/renfufei/article/details/