原文地址:http://blog.griddynamics.com/2011/06/understanding-gc-pauses-in-jvm-hotspots.html

Stop-the-world pauses of JVM due to the work of garbage collector are known foes of java-based applications. HotSpot JVM has a set of very advanced and tunable garbage collectors, but to find optimal configuration it is very important to understand an exact mechanics of garbage collection algorithms. This article is first of the series explaining how exactly GC spends our precious CPU cycles during stop-the-world pauses. An algorithm for young space garbage collection in HotSpot is explained in this post.

Structure of heap
Most of modern GCs are generational. That means that java heap memory is separated into few "spaces". Spaces are usually distinguished by “age” of resident objects. Objects are allocated in young space, then eventually copied to old (or tenured) space, if they survive long enough. This principle is based on hypothesis that most object “die young”, i.e. majority of objects become garbage shortly after being allocated. All HotSpot garbage collectors separate memory into 5 spaces (though for G1 collector spaces may be not continuous).

 

• Eden are space there objects are allocated,
• Survivor spaces are used to receive object during young (or minor GC),
• Tenured space is for long lived objects,
• Permanent space is for JVM own objects (like classes and JITed code), it is behaves just like tenured space so we will ignore it for rest of article.
Eden and 2 survivor spaces together are called young space.

 
HotSpot GC algorithms overview
HotSpot JVM is implementing few algorithms for GC which are combined in few possible GC profiles. 
• Serial generational collector (-XX:+UseSerialGC).
• Parallel for young space, serial for old space generational collector (-XX:+UseParallelGC).
• Parallel young and old space generational collector (-XX:+UseParallelOldGC).
• Concurrent mark sweep with serial young space collector (-XX:+UseConcMarkSweepGC 
–XX:-UseParNewGC).
• Concurrent mark sweep with parallel young space collector (-XX:+UseConcMarkSweepGC 
–XX:+UseParNewGC).
• G1 garbage collector (-XX:+UseG1GC).
All profiles except G1 are using almost same young space collection algorithms (with serial vs parallel variations).
 
Write barrier
Key point of generational GC is what it does need to collect entire heap each time, but just portion of it (e.g. young space). But to achieve this JVM have to implement special machinery called “write barrier”. There 2 types of write barriers implemented in HotSpot: dirty cards and snapshot-at-the-beginning (SATB). SATB write barrier is used in G1 algorithms (which is not covered in this article). All other algorithms are using dirty cards.
 
Dirty cards write barrier
Principle of dirty card write-barrier is very simple. Each time when program modifies reference in memory, it should mark modified memory page as dirty. There is a special card table in JVM and each 512 byte page of memory has associated byte in card table.
 
Young space collection algorithm
Almost all new objects (there are few exception when new object can be allocated directly in old space) are allocated in Eden space. To be more effective HotSpot is using thread local allocation blocks (TLAB) for allocation of new objects, but TLAB themselves are allocated in Eden. Once Eden becomes full minor GC is triggered. Goal of minor GC is to clear fresh garbage in Eden space. Copy-collection algorithm is used (live objects are copied to another space, and then whole space is marked as free memory). But before start collecting live objects, JVM should find all root references. Root references for minor GC are references from stack and all references from old space.
Normally collection of all reference from old space will require scanning through all objects in old space. That is why we need write-barrier. All objects in young space have been created (or relocated) since last reset of write-barrier, so non-dirty pages cannot have references into young space. This means we can scan only objects in dirty pages.
 
 Once initial reference set is collected, dirty cards are reset and JVM starts coping of live objects from Eden and one of survivor spaces into other survivor space. JVM only need to spend time on live objects. Relocating of object also requires updating of references pointing to it.
 
Finally we have Eden and one survivor space clean (and ready for allocation) and one survivor space filled with objects.
 
Object promotion
If object is not cleared during young GC it will be eventually copied (promoted) to old space. Promotion occurs in following situations:
• -XX:+AlwaysTenure  makes JVM to promote objects directly to old space instead of survivor  space (survivor spaces are not used in this case).
• once survivor space is full, all remaining live object are relocated directly to old space.
• If object has survived certain number of young space collections, it will be promoted to old space (required number of collections can be adjusted using –XX:MaxTenuringThreshold option and 
–XX:TargetSurvivorRatio JVM options).
 
Allocation of new objects in old space
It would be beneficial if we could possibly allocate long lived objects directly in old space. Unfortunately there is no way to instruct JVM to do this for particular object. But there are few cases when object can be allocated directly in old space.
• Option -XX:PretenureSizeThreshold=n instructs JVM what all objects larger  than n bytes should be allocated directly in old space (though if object size fits TLAB, JVM will allocate it in TLAB and thus young space, so you should also limit TLAB size).
• If object is larger than size of Eden space it also will be allocated in old space.
Unlike application objects, system objects are always allocated by JVM directly in permanent space.
 
Parallel execution
Most of task during young space collection can be done in parallel. If there are several CPUs available, JVM can utilize them to compress duration of stop-the-world pause during collection. Number of threads can be configured in HotSpot JVM by –XX:ParallelGCTreads=n parameter. By default JVM will choose number of thread by number of available CPU. As expected, serial version of collector will ignore this parameter because it can use only one CPU. Using parallel collection reduces time of stop-the-world pause by factor close to number of physical cores.
 
Measuring stop-the-world pause for young collection
Young space collection happens during stop-the-world pause (all non-GC-related threads in JVM are suspended). Wall clock time of stop-the-world pause is very important factor for applications (especially applications requiring fast response time). Parallel execution affects wall clock time of pause but not work effort to be done. 
Let’s summarize components of young GC pause. Total pause time can be written as:
Tyoung = Tstack_scan + Tcard_scan + Told_scan+ Tcopy ; there Tyoung is total time of young GC pause,Tstack_scan is time to scan root in stacks, Told_scan  is time to scan roots in old space and Tcopy is time to copy live objects (1).
 
Thread stack are usually very small, so major factors affecting time of young GC is Told_scan and Tcopy.
Another important parameter is frequency of young GC. Period between young collections is mainly determined by application allocation rate (bytes per second) and size of Eden space.
 
Pyoung = Seden / Ralloc ; there Pyoung  is period between young GC, Seden is size of Eden and Ralloc is rate of memory allocations (bytes per second) (2).
 
Tstack_scan – can be considered application specific constant.
Tcard_scan – is proportional to size of old space. Literally, JVM have to check single byte of table for each 512 bytes of heap (e.g. 8G of heap -> 16m to scan).

Told_scan  – is proportional to number of dirty cards in old space at the moment of young GC. If we assume that references to young space are distributed randomly in old space, then we can provide following formula for time of old space scanning.

; there Sold is size of old space and Dkcard and ncard are coefficients specific for application (3).
 
Tcopy – is proportional to number of live objects in heap. We can approximate it by formula:
 
 

 
 
There kcopy is effort to copy object, Rlong_live is rate of allocation of long lived objects, ksurvive = Rlong_live Ralloc (ksurvive usually very small), andktenure is a coefficient to approximate aging of object in young space before tenuring (ktenure ≥ 1) (4).
Now we can analyze how various JVM options may affect time and frequency of young GC.
 

Size of old space. Size of old space is affecting Tcard_scan and Told_scan part of young GC pause time according to formulas above. So we as we are increasing size of old space (read total heap size) time of young GC pauses will grow and it can be helped. After certain size of heap (usually 4-8 Gb) time of young collection is dominated by Tcard_scan (technically Tcopy can be even greater than Tcard_scan, bur it usually can be controlled by tuning of GC options).
 
HotSpot JVM options: -Xmx=n, -Xms=n
 
Size of Eden space. Period between young GC is proportional to size of Eden. Tcopy is also proportional to size of eden but in practice ksurvive can be so small that for some applications we can forget about Tcopy. Unfortunately time between young GC will also affect coefficient D in equation (4). Though dependency between D and Pyoung is very application specific, increasing Pyoung will increase D and as a consequence Tscan_old.
 
HotSpot JVM options: -XX:NewSize=n, -XX:MaxNewSize=n
 
Size of survivor space. Size of survivor space puts hard limit of how much objects can stay in young space between collections. Changing size of survivor space may affect ktenure (or mat not, e.g. ifktenure is already 1).
 
HotSpot JVM options: -XX:SurviorRatio=n
 
Max tenuring threshold and target survivor ratio. These two JVM options also allow artificially adjustktenure.
 
HotSpot JVM options: -XX:TargetSurviorRatio=n, -XX:MaxTenuringThreshold=n , -XX:+AlwaysTenure, -XX:+NeverTenure
 
Pretenuring threshold. For some applications using pretenuring threshold could reduce ksurvive due to allocation of long lived object directly in old space.
 
HotSpot JVM options: -XX:PretenureThreshold=n

Understanding GC pauses in JVM, HotSpot's minor GC.的更多相关文章

  1. 为什么在进行Full GC之前最好进行一次Minor GC

    摘自:<Java Performance>第三章 为什么在进行Full GC之前最好进行一次Minor GC? Garbage collecting the young generatio ...

  2. Hotspot的minor GC

    内容来自<java性能优化>. 上图展示了Hotspot minor GC的过程:eden中的存活对象和from中"不够老"的对象,被移动到to中,from中" ...

  3. JVM 垃圾回收 Minor gc vs Major gc vs Full gc

    关于垃圾回收机制及比较请参见:http://colobu.com/2015/04/07/minor-gc-vs-major-gc-vs-full-gc/ http://colobu.com/2014/ ...

  4. JVM垃圾回收(二)- Minor GC vs Major GC vs Full GC

    Minor GC vs Major GC vs Full GC 垃圾回收的活动会清理对内存中的不同区域,这些事件一般被称为Minor,Major以及Full GC events.本章我们会讨论这些清理 ...

  5. Java虚拟机6:内存溢出和内存泄露、并行和并发、Minor GC和Full GC、Client模式和Server模式的区别

    前言 之前的文章尤其是讲解GC的时候提到了很多的概念,比如内存溢出和内存泄露.并行与并发.Client模式和Server模式.Minor GC和Full GC,本文详细讲解下这些概念的区别. 内存溢出 ...

  6. Java GC机制中Minor GC/Full GC

    Minor GC Young GC Full GC Major GC https://blog.csdn.net/chenleixing/article/details/46706039 内存划分为 ...

  7. JVM内存分配及GC简述

    在阐述JVM的内存区域之前,先来看下计算机的存储单位.从小到大依次为Bit,Byte,KB,MB,GB,TB.相邻的单位相差2的10次方. 计算机运行中的存储元件主要分为寄存器(位于CPU)和内存,寄 ...

  8. Minor GC、Major GC、Full GC、分配担保

    转载:http://www.importnew.com/15820.html 空间分配担保 区别 在 Plumbr 从事 GC 暂停检测相关功能的工作时,我被迫用自己的方式,通过大量文章.书籍和演讲来 ...

  9. JVM内存模型和GC机制

    目录 1.JVM内存模型 2.GC 1.JVM内存模型 堆,栈,本地方法栈,方法区,程序计数器 2.GC 新生代收集器:Serial(单线程).ParNew.Parallel Scavenge: 老年 ...

随机推荐

  1. 一个小程序,时间util

    比较时间,如果此时间是今天的显示时间点,今天以前显日期 public String getTime(Date time){               SimpleDateFormat dateFor ...

  2. Dota兄订餐——静态代理(java)

    理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼得水,享受游刃有余的乐趣. 代理模式是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,Pr ...

  3. SQLServer中使用索引视图(物化视图)

    物化视图:以前用的普通的视图,普通视图就是一段逻辑语句,对性能没有任何的提升,也不能创建索引,而物化视图会把视图里查询出来的数据在数据库上建立快照,它和物理表一样,可以创建 索引,主键约束等等,性能会 ...

  4. 关于配置tnsnames来使用PLSQL连接数据库

    关于配置tnsnames来使用PLSQL连接数据库 要想用ORACLE SQLdeveloper或者第三方工具PLSQLdeveloper.Toad等连接ORACLE数据库,必需要配置TNSnames ...

  5. android shape的使用详解以及常用效果(渐变色、分割线、边框、半透明阴影效果等)

    shape使用.渐变色.分割线.边框.半透明.半透明阴影效果. 首先简单了解一下shape中常见的属性.(详细介绍参看  api文档 ) 转载请注明:Rflyee_大飞: http://blog.cs ...

  6. Android的Touch系统简介(一

    一.Android touch事件的相关概念 用户的Touch事件被包装成MotionEvent 用户当前的touch事件主要类型有: ACTION_DOWN: 表示用户开始触摸. ACTION_MO ...

  7. MySQL如何有效地创建基于 INNODB 引擎的表

    2016-05-27 赵伟 数据库开发者 有用户问我们为什么下面这个建表语句会执行失败,报错是 "Row size too large ...."下面我就以这个例子出发讲一讲使用m ...

  8. 一些Linux优化方法

    1. 利用栈做备胎,减少分配空间的几率,IO自己有一份缓存,如果超了就使用stack空间 2. 分散IO:代表readv,可以通过一次系统调用,将内容读到分散的缓存中,可以减少系统的系统调用

  9. HTML5 ArrayBuffer:类型化数组 (二)

    类型化数组是JavaScript操作二进制数据的一个接口. 这要从WebGL项目的诞生说起,所谓WebGL,就是指浏览器与显卡之间的通信接口,为了满足JavaScript与显卡之间大量的.实时的数据交 ...

  10. [转]delphi 删除动态数组的指定元素

    type TArr = array of TPoint; {把数组先定义成一个类型会方便许多, 这里仅用 TPoint 测试} {删除动态数组指定元素的过程: 参数 arr 是数组名, 参数 Inde ...