`
ayufox
  • 浏览: 276192 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

JVM内存管理和垃圾回收

    博客分类:
  • JVM
阅读更多

Java虚拟机的一个强大之处在于其提供垃圾自动回收,对开发人员掩盖了内存分配和回收的细节。本篇将探索JVM的内存分配和垃圾回收机制,以在内存分析实战中提供一些理论和实践参考。
1.    从理论开始
1.1.垃圾检测
任何虚拟机的回收算法都包括两个步骤:检测垃圾和回收垃圾。当一个对象被创建时,其是活动的对象,此时其是可用的,而在运行过程中,该对象的引用不再被使用,这时该对象就成为垃圾,一般采用两种方式来区别活动对象和垃圾对象:引用计数和跟踪。当一个对象被其它对象引用时,其引用计数加1,当不再被其它对象引用时,计数减1,当其引用计数为0时,该对象就成为垃圾,引用计数的缺点是无法检测循环引用和维护引用计数的代价,在现代虚拟机中一般不采用该方式。而跟踪指的是虚拟机追踪从根对象出发的有向对象图,如果一个对象不能被追踪到,则该对象为垃圾,采用追踪算法的垃圾回收器也叫标记并回收回收器(见下图,可以形象地理解为在堆空间中引入了重力场,参见http://developer.51cto.com/art/200610/32793.htm)。
 
图1 初始状态
 
图2 TR1-A链和TR2-D链断开,A、B、C、D掉入回收池
 
图3 A、B、C、D四个对象被回收
1.2.避免堆碎片
在进行垃圾回收之后,由于内存分配时,垃圾对象和活动对象可能相邻存在,则可能会在堆中出现堆碎片,采用标记并回收回收器的虚拟机一般采用两种方法来对付堆碎片:压缩和拷贝。压缩回收是指当进行垃圾回收之后,将剩下的活动对象推向堆的另一端,则当垃圾回收完毕之后在另一端形成连续的堆。拷贝回收指的是保持两个同样大小的堆,在对一个队进行垃圾回收过程中,对于检测出来的活动对象拷贝到另一个堆并连续存放。参见下图
 
图4 拷贝收集和压缩手集
1.3.分代回收
拷贝回收的一个缺点在于有些对象是长期存在的,但在回收过程中仍然必须将这些对象多次拷贝,分代回收指的是,对不同年龄(在内存存在的时间的长短)将对象放入不同的代堆中,并对不同的代堆采用不同的回收算法。事实上,大部分的对象属于“短命”对象,我们可以更多地对年轻的代堆进行垃圾回收,而对于年老的代堆则减少回收频度。
1.4.垃圾回收器设计决策
    顺序执行垃圾回收VS并行垃圾回收:在顺序执行垃圾回收器中,即使系统拥有多个处理器,也只有一个处理器会执行垃圾回收,相比之下,并行垃圾回收具备更好的垃圾回收性能,但因此必定引入更多的复杂性和潜在的内存碎片。
    并发执行VS停止并回收:停止并回收指在进行垃圾回收时停止应用线程的执行,而并发执行垃圾回收器在大部分情况下与应用线程并发执行,当然,部分操作仍然需要在停止应用线程的情况下执行,并发回收对应用线程的停止时间更短,但相比而言,并发执行垃圾回收器将占用更多的空间并有可能对系统性能产生影响。
    压缩VS不压缩VS拷贝:随着对象的消亡,JVM的堆空间将不可避免地存在碎片:一种方式是对碎片进行压缩,付出的代价是垃圾回收时更多的操作,得到的好处是能够快速分配;一种方式是不进行压缩,好处是垃圾回收更快,但分配算法将更加复杂;另外一种是拷贝,即将存活的对象拷贝到一个新的空间段上,之后将旧的对象全部销毁,好处是垃圾回收快,内存分配快,但必须付出更多的空间代价。
1.5.性能度量
    吞吐量(Throughput):吞吐量 = (总执行时间-垃圾回收时间)/总执行时间
    暂停时间(Pause time):垃圾回收导致的应用的暂停时间
2.    Sun HotSpot JVM实战
2.1.JVM分代垃圾回收
JVM的堆空间分成年轻代(Young Gen)、年老代(Old Gen)和持久代(Perm Gen),其中年轻代用于放置新创建的对象,而对象在经过几次的垃圾回收后仍然没有被回收,则将其转移到年老代,持久代用于放置一些为JVM本身的方便性而使用的对象,譬如类定义、方法定义、常量、代码段等。年轻代又分为一个Eden区和两个Survivor区, 而总有一个Survivor区是空的,随着每一次的垃圾回收,从Eden区和非空Survivor区的存活对象拷贝到空Survior区,如果Survior空间不足,则直接拷贝到年老区中,并将刚经历过回收的区空间返回到堆空间,此时两个Survivor的角色做了个转换(空的变成非空,非空的变成空的)。当一个对象经过多次回收仍然存在,则将其转入年老区。Sun HotSpot JVM对不同代将使用不同的垃圾回收算法。
 
图5 Sun HotSpot VM堆分代
 
图6 年轻代垃圾回收示意图
2.2.内存分配
对于大块的连续内存,使用bump-the-pointer技术,内存分配将非常简易和快速。对于多线程的场景,情况稍微复杂,内存分配必须是线程安全的,这可能导致内存分成为系统的瓶颈。Sun HotSpot JVM使用所谓的Thread-Local Allocation Buffers (TLABs)技术来解决这个问题,通过指定给每个线程一定的Buffer空间,线程在内存分配时,将尽量从此空间上分配,由于空间是独享的,因此分配将非常地快速,当然相应的,可能会造成空间的浪费。
2.3.不同垃圾回收器比较
2.3.1.垃圾回收方式
垃圾回收器名称    年轻代回收    年老代回收    压缩
Serial Collector    单线索程,顺序回收    单线程,顺序回收    是
Parallel Collector    多线程,并行回收    单线程,顺序回收    是
ParallelCompacting Collector    多线程,并行回收    多线程,并行回收    是
Concurrent Mark-Sweep (CMS) Collector    多线程,与应用并发回收    多线程,与应用并发回收    否
2.3.2应用场景
    Serial Collector:适用于客户端应用程序,并且对暂停时间要求不严格,能够有效地管理64M左右的内存,垃圾回收导致的暂停时间在半秒内
    Parallel Collector:适用于多处理器的服务器,并且对暂停时间要求不严格,譬如批处理等
    ParallelCompacting Collector:适用于多处理器的服务器,并且对暂停时间稍微严格的应用
    Concurrent Mark-Sweep (CMS) Collector:适用于多处理器的服务器,并且对暂停时间非常严格的应用
2.3.3.Sun HotSpot JVM参数自动调整
2.3.3.1.server和client模式
    除了32位的windows系统,只要服务器拥有2+个处理器单元和2G+的系统内存,虚拟机自动识别为server模式,否则为client模式
    可以通过在启动参数中指定-server或者-client来指定使用的模式
    Client模式默认使用serial garbage collector,初始4M、最多64M的堆内存
    Server模式默认使用parallel collector,初始1/64的物理内存最多不超过1G、最多1/4的物理内存最多不超过1G
    可以通过指定特定的参数来覆盖默认的参数
2.3.3.2.Parallel Collector根据设定的目标自动调整
    指定暂停时间目标:通过指定-XX:MaxGCPauseMillis=n启动参数来设定最大的暂停时间目标,单位为毫秒,虚拟机自动根据该目标来调整各个代空间的大小,当然,有时会也会无法达到目标,另外,该参数可能会降低系统的吞吐量。默认情况下,虚拟机不指定暂停时间。
    指定吞吐量目标:通过指定-XX:GCTimeRatio=n 启动参数来设置最低的吞吐量目标,其中,n = 1 / (1-吞吐量) – 1,譬如预定的吞吐量为95%,则n = 1 / 5% - 1 = 19,虚拟机自动根据该目标自动调整各个代空间的大小,注意,该参数可能会加到垃圾回收导致的暂停时间。虚拟机默认目标吞吐量是99%。
2.4.常用的Sun HotSpot JVM启动参数
2.4.1.指定垃圾回收器
    –XX:+UseSerialGC:使用Serial Collector
    –XX:+UseParallelGC:使用Parallel Collector
    –XX:+UseParallelOldGC:使用ParallelCompacting Collector(JDK6+)
    –XX:+UseConcMarkSweepGC:使用Concurrent Mark-Sweep (CMS) Collector
2.4.2.Parallel and Parallel Compacting Collectors参数
    –XX:ParallelGCThreads=n(默认为处理器数):并发垃圾回收线程数
    –XX:MaxGCPauseMillis=n和–XX:GCTimeRatio=n:见2.4.2说明
2.4.3.CMS Collector参数
    –XX:+CMSIncrementalMode(默认为disable):启用垃圾回收增量模式,该模式可降低因垃圾回收导致的暂停时间
    –XX:ParallelGCThreads=n(默认为处理器数):并发垃圾回收线程数
    –XX:+CMSIncrementalPacing(默认为disable):与上一个参数配合使用,根据应用程序的行为自动调整每次执行的垃圾回收任务的幅度(或比例?)(原文:Enables automatic control of the amount of work the CMS collector is allowed to do before giving up the processor, based on application behavior.)
    -XX:CMSIncrementalDutyCycle=<N> (default: 5):每次增量回收垃圾的占总垃圾回收任务的比例,如果参数CMSIncrementalPacing指定,则指的是初始比例。(原文:This is the percentage (0-100) of time between minor collections that the concurrent collector is allowed to run. If CMSIncrementalPacing is enabled, then this is just the initial value.)
    -XX:CMSIncrementalDutyCycleMin=<N> (default: 10):与CMSIncrementalPacing参数配合使用,每次增量回收垃圾的占总垃圾回收任务的最小比例(原文:This is the percentage (0-100) which is the lower bound on the duty cycle when CMSIncrementalPacing is enabled.)
2.4.4.垃圾回收统计(系统剖析和性能调优使用)
    –XX:+PrintGC:打印每次垃圾回收的基本信息
    –XX:+PrintGCDetails:打印每次垃圾回收的详细信息
    –XX:+PrintGCTimeStamps:在每次垃圾回收时打印时间,与上两个参数之一结合使用
2.4.5.堆空间和代空间设置
    –Xmsn:初始堆空间,譬如-Xms512M
    –Xmxn:最大堆空间,譬如-Xmx1024M,一般可指定这两个参数一致以避免在系统运行期间进行堆空间的调整
    –XX:MinHeapFreeRatio=minimum(默认40):当代空闲空间在代空间中比例大于maximum时,自动减少代空间以小于该值
    –XX:MaxHeapFreeRatio=maximum(默认70):当代空闲在代空间中比例小于minimum时,自动增长代空间以大于该值
    –XX:NewSize=n:默认年轻代空间的大小,譬如–XX:NewSize=400M
    –XX:NewRatio=n(默认server模式是8,client模式是2):年轻代空间与年老代空间的比例
    –XX:SurvivorRatio=n(默认是32):Eden区与Survivor区的比例,譬如–XX:SurvivorRatio=7,则每个Survivor区占整个年轻代空间的1/9(注意,有两个Survivor区)
    –XX:MaxPermSize=n:持久区大小,譬如–XX:MaxPermSize=128M
3.    装备我们的工具箱
3.1.内存剖析(jmap+jhat)
3.1.1.命令
    Jps:与ps命令类似,显示java进程的进程号
    Jmap: 统计当前虚拟机的堆内存数据,一般使用如下:jmap –dump:file=filename {pid},将统计数据dump到filename文件中
    Jhat(Java Heap Analysis Tool):将上一个命令的统计数据文件分析后以html的方式展现,一般使用如下:jhat –J-mx512M filename
3.1.2.常用的统计数据
    在jhat程序运行后,访问http://{server}:7000查看统计数据
3.1.2.1.每个类的实例数(按实例数从多到少排序)
 
图7 类实例数统计截图
3.1.2.2.每个类的实例数和占用空间数(按占用空间数从大到小排序)
 
图8 类实例占用空间统计截图
3.1.2.3.每个类的引用统计(如下是String被其它类的实例引用的次数统计,按引用次数从多到少排序)
 
图9 类java.lang.String引用截图案
3.2.虚拟机监控(jconsole)
http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html
3.3.综合剖析工具(jprofiler)
Jprofiler是一个功能非常强大的性能剖析工具,但其对系统的性能影响非常之大,一般只能用于测试环境的性能剖析,特别是执行时间统计剖析。入门使用可参见如下的链接
http://www.blogjava.net/ddpie/archive/2007/05/14/117450.html
4.    参考文档
    <<Memory Management in the Java HotSpot™ Virtual Machine>>
    <<Java SE 6 HotSpot™  Virtual Machine Garbage Collection Tuning >>
    << Garbage Collector Ergonomics>>
    <<深入JAVA虚拟机>>

分享到:
评论
2 楼 Clayz 2008-11-05  
mark。楼上的也太狠了吧...
1 楼 mineral 2008-09-23  
非常好的文章,已收藏并作为公司培训教程。

相关推荐

    JVM内存管理和垃圾回收.pdf

    Java虚拟机(JVM)内存管理和垃圾回收是Java编程中至关重要的概念,它涉及到...总之,JVM内存管理和垃圾回收是优化Java应用性能的关键。了解这些概念并正确配置JVM参数,可以帮助开发者创建更高效、更稳定的软件系统。

    JVM内存管理和垃圾回收参考.pdf

    Java虚拟机(JVM)内存管理和...总结来说,JVM内存管理和垃圾回收是一个复杂而精细的过程,涉及多种策略和算法,旨在高效利用内存,减少应用暂停时间,并防止内存泄漏。理解和掌握这些原理对优化Java应用性能至关重要。

    jvm内存管理和垃圾回收

    很久之前就一直在学习JVM,但是一直也没有好好的总结,最近终于有了空闲,将之前学习的内容整理成了一个PPT。 也希望大神们可以批评指正。 ppt中主要包含下面几部分: Java内存模型 内存分配策略 分代垃圾收集...

    JVM内存管理和垃圾回收知识.pdf

    Java虚拟机(JVM)内存管理和垃圾回收是Java编程中至关重要的概念,它涉及到程序的性能和稳定性。本文主要探讨了JVM如何处理内存分配、垃圾检测与回收,以及各种策略和性能指标。 首先,垃圾回收是JVM的一项核心...

    JVM内存分配与垃圾回收详解

    JVM 内存分配与垃圾回收详解 Java 虚拟机(JVM)是 Java 语言的 runtime 环境,它提供了一个平台独立的方式来执行 Java 字节码。JVM 内存分配与垃圾回收是 JVM 中两个非常重要的概念,本文将对 JVM 内存分配与垃圾...

    JVM内存管理和JVM垃圾回收

    理解JVM内存管理和垃圾回收机制对于优化Java应用的性能至关重要。开发者可以根据应用的需求和特点,通过调整JVM参数来选择合适的内存配置和垃圾回收策略。同时,使用如JVisualVM等工具进行实时监控和分析,可以帮助...

    JVM内存模型以及垃圾回收相关资料

    JVM内存模型与垃圾回收是...总的来说,理解JVM内存模型和垃圾回收机制对于优化Java应用性能至关重要,它涉及到内存分配策略、垃圾收集算法的选择以及内存参数的调整,这些都需要开发者具备深入的JVM知识和实践经验。

    jvm内存模型以及垃圾回收机制.pptx

    Java虚拟机(JVM)内存模型...理解JVM内存模型和垃圾回收机制对于优化Java应用性能、避免内存泄漏和有效利用资源至关重要。开发者应根据实际需求选择合适的垃圾回收器,并关注内存分配策略,以实现高效稳定的程序运行。

    JVM 内存分代、垃圾回收漫谈.docx

    Java虚拟机(JVM)内存管理是Java程序性能优化的关键环节。...理解JVM内存管理和垃圾回收机制对于诊断和解决OOM问题至关重要。通过调整JVM参数,优化垃圾回收策略,可以有效地防止内存溢出,提升应用的稳定性和性能。

    JVM性能调优-JVM内存整理及GC回收.pdf

    Java虚拟机(JVM)性能调优涉及到许多关键概念,其中最重要的一个是JVM内存管理和垃圾回收(GC)。本文将深入探讨这些主题。 首先,我们要澄清Java中的参数传递机制。Java中,无论是基本类型还是对象引用,都在运行...

    JVM面试资料:JVM结构、JVM调优、四大垃圾回收算法、七大垃圾回收器

    四大垃圾回收算法:复制算法、标记-清除算法、标记-整理算法、分代收集算法 七大垃圾回收器:Serial、Serial Old、ParNew、CMS、Parallel、Parallel Old、G1 JVM调优:命令行指令,设置堆内存大小的参数

    JVM内存优化、垃圾回收、内存分析知识

    认识JVM内存优化, 避免最大的误区:认为JVM内存越大越好。看到一个线程 blocked就认为阻塞了。

    jvm内存和垃圾回收.xmind

    自己总结的jvm中内存和垃圾回收的笔记,绘制了详细的思维导图,每个思维导图中均有详细的博文解释,方便大家学习和理解,免费分享给大家。适合jvm的爱好者和学习者

    jvm内存基本结构及垃圾回收

    理解JVM内存结构和垃圾回收机制对于Java开发者至关重要,它可以帮助我们更好地优化程序性能,避免内存溢出等问题。通过调整JVM参数,如堆大小、新生代与老年代的比例、垃圾收集器的选择等,我们可以根据应用的需求...

    JVM历史发展和内存回收笔记

    本文将详细探讨JVM的发展历程以及内存管理中的垃圾回收机制。 一、JVM的历史发展 1. **早期阶段**:1995年,Sun Microsystems发布了Java的第一个版本,JVM作为其核心组成部分,主要应用于嵌入式设备和网络应用。初...

    JVM入门实战/arthas实战/垃圾回收算法/垃圾回收器/jvm内存模型分析

    第二节:JVM内存模型 1.1 概念 1.2 JVM内存模型 1.3 Heap堆内存模型 第三节:定位垃圾对象的依据 1.1 引用计数法 1.2 可达性算法 第四节:垃圾回收算法 1.1标记清除算法 1.2复制算法 1.3 标记整理(标记压缩)...

    jvm内存模型以及垃圾回收机制.rar

    在实际开发中,理解JVM内存模型和垃圾回收机制对于优化应用程序性能、避免内存泄漏和有效利用资源至关重要。通过调整JVM参数,如堆大小、新生代和老年代的比例、垃圾收集器的选择等,可以改善程序的运行效率和稳定性...

Global site tag (gtag.js) - Google Analytics