`
longdick
  • 浏览: 584926 次
  • 性别: Icon_minigender_1
  • 来自: 0
社区版块
存档分类
最新评论

三种GC大揭秘

    博客分类:
  • JVM
阅读更多

/**

*  转载请注明作者longdick    http://longdick.iteye.com

*

*/

 

(本文基于JDK6)

 

说到GC,首先要对Java 的内存模型有所了解。

Java 的内存模型各个代的默认排列有如下图(适用JDK1.4.*  到 JDK6):


Java 的内存模型分为

Young(年轻代)

Tenured(终身代)

Perm(永久代)

 

更多关于内存模型的文章看这里:

图解JVM在内存中申请对象及垃圾回收流程

图解JVM内存模型

 

在堆内存中的GC可以分为Minor GC(次要GC)和 Major GC(主要GC),次要GC是在年轻代进行收集的GC,职责是在Eden区满的时候收集dead的对象和转移存活的对象;主要GC是在终生代满时进行收集的GC,主要GC较次要GC需要更多时间。
使用jvm参数-verbose:gc 就可以输出每一次GC的详细信息。

你可能在程序运行起来以后看到如下输出:

 

[GC 325407K->83000K(776768K), 0.2300771 secs]
[GC 325816K->83372K(776768K), 0.2454258 secs]
[Full GC 267628K->83769K(776768K), 1.8479984 secs]





你可以看到两次Minor GC(次要GC)和一次Major GC(主要GC)。

325407K->83000K   箭头前后的数字分别代表收集前和收集后的堆内存占用情况。
(776768K) 括号内的数字代表总共分配的堆内存空间,注意,这个值不包括其中一个Survior空间,也不包括 permanent generation(永久代)。

最后的时间0.2300771 secs指的是GC所耗费的时间。

 

如果运行时加上VM参数-XX:+PrintGCDetails    将输出更详细的信息。如下显示了Eden区和Heap内存在GC前后的变化:

 

[GC [DefNew: 64575K->959K(64576K), 0.0457646 secs] 196016K->133633K(261184K), 0.0459067 secs]




 

如果运行时加上VM参数-XX:+PrintGCTimeStamps 则可以得到GC发生的时间。

以下输出显示了在程序运行到111.042 秒的时候发生的GC,包括一次在Eden区的次要GC和发生在Tenured区的主要GC:

 

111.042: [GC 111.042: [DefNew: 8128K->8128K(8128K), 0.0000505 secs]111.042: [Tenured: 18154K->2311K(24576K), 0.1290354 secs] 26282K->2311K(32704K), 0.1293306 secs]

 

GC性能主要的衡量指标有两个:Throughput和Pauses。吞吐量(Throughput)是不做GC的时间与总时间的百分比,分子包括分配内存空间的时间。中断(Pauses)是测量时间段内由于GC而导致的应用暂停次数。

对用户而言,对GC的需求往往是不一样的。一般的web应用对吞吐量要求不高,由于GC而引起的偶尔中断也是可以容忍的。然而一个交互性强的实时应用系统来说,经常性的中断将带来糟糕的用户体验。

即时性(Promptness)和足印(footprint)也是某些用户考虑的问题。 即时性是对象死去到所占内存释放的时间间隔,这个指数是分布式应用如使用RMI的分布式应用的一项需要考虑的因素。足印是一种过程的集合,代表可伸缩性。

 

 

HOTSPOT JVM总共拥有3种不同的GC,各有各总自的特点和应用场景:

 

  • serial collector (串行GC)任何时刻都是使用一个线程执行GC操作,这种GC在线程间通信没有大的开销的应用会有相对不错的运行效率。最适合单处理器的系统;多处理器系统对这种GC而言并不能提升收集的效率。JVM默认情况下就是使用这个GC,这种GC有个形象的别名叫做"stop-the-world",当JVM在用这个GC收集垃圾的时候,你的app别想干其他事。你也可以用这个参数 -XX:+UseSerialGC 显式的声明使用。 默认的serial gc可以应付绝大多数的app。除非以下情况:这是一个运行在大内存多处理器的机器上的多线程的大应用。
  • parallel collector (并行GC,或者叫 throughput collector ) 会以并行的方式运行minor collections(次级GC), 能较大的减少GC的开销。其诞生的初衷就是专门给运行在多处理器,多线程硬件上的中大型应用的。在特定的硬件和OS环境条件下这是默认选项,显式声明使用 -XX:+UseParallelGC 参数。始于JDK1.3.1。 parallel compaction 是在 J2SE 5.0 update 6引入的新特性,并在Java SE 6 得到增强。它允许使用并行的方式运行Major collections(主要GC)。如果不开启parallel compaction, major collections 将以单一线程的方式运行。 通过参数 -XX:+UseParallelOldGC 显式使用该特性。
  • concurrent collector (同步GC)同时运行大多数的任务 (GC的同时应用也在运行)来保证GC引起的中断时间尽量的短。主要应用在实时性要求重于总体吞吐量要求的中大型应用,即使如此,降低中断时间的技术还是会导致应用程序性能的少许降低。可以使用参数 -XX:+UseConcMarkSweepGC 使用该特性。

 

parallel collector的一些注意点:

parallel collector从JDK5开始就是Server端JVM的默认选择,需要加VM参数 -server

parallel collector还采用一些细节调优的策略如:

  • 限定最大GC中断时间
  • 吞吐量限定
  • 足印(伸缩量)设定

可以用vm参数 -XX:MaxGCPauseMillis=<N> 来限定最大GC中断时间,单位是ms,规定GC产生的中断时间不能超过指定的时间。默认没有这个限制。一旦使用了这个参数,heap空间和其他相关参数会做出相应的调整来满足最大GC中断时间的要求。

吞吐量限定使用-XX:GCTimeRatio=<N> 来设定GC时间的比率,N 的值 = 没有花在GC上的时间/GC的时间 因此GC的时间占用总时间的百分比公式= 1 / (1 + <N>) 。比如 -XX:GCTimeRatio=19 意味着将有1/20的时间花在GC上。默认值=99。

 

足印(伸缩量)实际上就是heap堆内存的调整。最大Heap容量使用参数 -Xmx<N> 声明。

 

以上参数中任何一个的改动,都会引起另外两个的改变。三者的优先级如上顺序一至。

如果太多时间黑白花费在GC上,parallel collector将抛出OOM,这临界值大概是98%;也可以使用-XX:-UseGCOverheadLimit 关闭这个特性。

 

concurrent collector的一些注意点:

 

不适用于单处理器的系统,事实上在单处理器系统上运行concurrent collector 效率反而降低。如果只能运行在单处理器的系统上,那记得开启增量模式(incremental mode)。

前面几种GC都是在Tenured区满了以后触发主要GC操作;concurrent collector却是在Tenured区满溢之前就进行主要GC。如果concurrent collector没有赶在Tenured区满前收集完或者还没有开始收集的话,就会产生长时间的中断。参数-XX:CMSInitiatingOccupancyFraction=<N> 可以指定触发主要GC的临界值,N(0-100)代表的是Tenured区饱和程度百分比。一旦Tenured区饱和程度达到这个临界值,主要GC就发生了。

 

concurrent collection的生命周期一般包括如下几步:

  • 停止应用的所有线程,标识出所有可到达的对象集合,然后恢复应用的所有线程
  • 使用一个或几个处理器资源同步跟踪可到达的对象,应用线程同时运行
  • 使用一个处理器资源同步地重新定位那些自从上一个步骤以来可能修改过的对象
  • 停止应用的所有线程,重新定位那些自从上一个步骤以来可能修改过的对象,然后恢复应用的所有线程
  • 使用一个处理器资源同步地收集不被引用的对象
  • 使用一个处理器资源同步地重新定义堆内存,并且为下一次GC生命周期作好数据准备

concurrent collection在整个收集的过程中,至少会占有一到两个处理器,而且不会自动放弃占有的处理器资源。

这个特性会让只有一到两个处理器的系统很难过。为处理这个问题,需要借助增量模式(incremental mode)。

 

增量模式 的核心思想是 将整个GC生命周期分解成一段段的时间块分步进行,以此减少中断的时间,但是不可避免的是伴随着吞吐量的下降。

使用参数 -XX:+CMSIncrementalMode 开启增量模式。

 

 

参考资料:

http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html

http://java.sun.com/j2se/1.5.0/docs/guide/vm/gc-ergonomics.html

  • 大小: 21.6 KB
17
2
分享到:
评论
5 楼 狂放不羁 2009-10-11  
concurrent collector (同步GC)

个人觉得,这个应该改为“并发GC”.O(∩_∩)0
4 楼 andey007518 2009-10-02  
lzy.je 写道
这个比前2篇写得有用的多。

任何知识的积累都不能用有用没用来下定论呢,这就像吃了9个饼还没饱,吃到第十个饼终于饱了,难道你就否认前9个饼对你的肚子没有贡献?呵呵
=============================================

这位大虾比较幽默,对于GC写的这么详细还是受用了,学无止境,谢谢LZ
3 楼 longdick 2009-09-28  
lzy.je 写道
这个比前2篇写得有用的多。

任何知识的积累都不能用有用没用来下定论呢,这就像吃了9个饼还没饱,吃到第十个饼终于饱了,难道你就否认前9个饼对你的肚子没有贡献?呵呵
2 楼 lzy.je 2009-09-24  
这个比前2篇写得有用的多。
1 楼 simplemx 2009-09-23  
非常感谢blog主,令我学到了非常多。

相关推荐

    揭秘Java虚拟机-JVM设计原理与实现

    《揭秘Java虚拟机-JVM设计原理与实现》这本书深入探讨了Java虚拟机(JVM)的工作原理及其在Java编程中的核心地位。Java虚拟机是Java平台的核心组成部分,它负责执行字节码,为开发者提供了跨平台的运行环境。以下是...

    spark内核揭秘

    《Spark内核揭秘》这本书是Spark亚太研究院的力作,旨在深入解析Spark这一大数据处理框架的核心机制,帮助读者理解Spark的工作原理,同时提供性能优化的实践指导。Spark作为当前广泛使用的分布式计算系统,其高效、...

    揭秘java虚拟机

    通过调整JVM参数,如堆大小、新生代和老年代的比例、GC策略等,可以改善应用程序的性能。理解和掌握JVM性能监控工具,如VisualVM、JConsole、JProfiler等,能够帮助我们有效地定位和解决性能问题。 总之,《揭秘...

    kafka-高性能揭秘及优化.pdf

    基于磁盘大文件的顺序读写;使用系统PageCache而不是应用内存缓存;支持多Disk Drive等。 Kafka的性能数据展示,在腾讯云上部署的Kafka能够处理日数万亿级别的消息,这得益于腾讯中间件团队基于业务实际情况对Kafka...

    JAVA架构知识库整理.pdf

    MinorGC的过程包括复制、清空和互换三个步骤。老年代通常存放生命周期较长的对象,采用标记整理算法回收。永久代则是存放类信息、常量等,随着Java8的发布,这部分内存被元空间(Metaspace)所替代。 关于垃圾回收...

    windows 2003 DNS系列详细教程

    在"揭秘DNS后台文件"部分,将介绍DNS服务器上的一些关键文件,如区域文件(如.zone文件)和日志文件,以及如何查看和分析这些文件以诊断问题或优化性能。 "亲手缔造DNS体系,创建DNS私有根"章节则针对需要在内部...

    程序员的面试模板及技巧资料.pdf,这是一份不错的文件

    - **垃圾回收(GC)**: 了解不同类型的GC(Minor GC, Full GC, CMS, G1等),GC的工作原理,以及如何优化内存管理。 - **JVM内存模型**: 包括堆内存、栈内存、方法区、本地方法栈等区域的用途和大小调整。 3. **...

    blog:fupengfei058的博客

    rand()随机数安全的深入理解mmap和madvise的使用php函数的实现原理及性能分析使用生成器优化foreachPHP发送HTTP请求的几种方式swoole4协程原理PHP中$_POST揭秘goroutine背后的系统知识goroutine并发控制与通信golang...

    一、JVM内存区域1

    对象的创建是通过 new 关键字来实现的,对象的内存布局包括对象头、实例数据和对齐填充三个部分。对象头包含对象自身的信息,如对象的标识、类信息、锁信息等。对象自身数据类型指针是对象头的一部分,指向对象的类...

    CoreFx源码

    《深入探索CoreFx源码——揭秘.NET Core的基石》 CoreFx是.NET Core框架的核心组件,它是.NET Core的基石,负责提供基础类库、运行时环境以及系统服务。对于想要深入理解.NET Core工作原理和机制的开发者来说,阅读...

    java performance

    - 揭秘JIT编译器的工作方式,如何将字节码转化为机器码,提升运行速度。 - 理解热点代码识别和优化机制,如方法的即时编译与逃逸分析。 7. **内存管理与内存泄漏**: - 对象生命周期和引用类型,了解软引用、弱...

    jdk-learning-project:jdk原始码学习

    2. **内部机制揭秘**:例如,深入理解垃圾回收(Garbage Collection)机制,包括不同的GC算法,如串行GC、并行GC、CMS、G1和ZGC等。 3. **反射机制**:通过源码,我们可以看到Class、Constructor、Method等类如何...

    CPythonInternals:这是一个存储库,其中包含CPython解释器的代码示例。 从Real Python上名为“ CPython Internals”的书中学习

    **CPython内核揭秘** **一、什么是CPython** CPython是Python编程语言的标准实现,它是用C语言编写的,因此得名CPython。它是一个开源项目,由Python社区的开发者们共同维护和更新。CPython是大多数Python开发者的...

Global site tag (gtag.js) - Google Analytics