`
irfen
  • 浏览: 202706 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java虚拟机垃圾回收机制

阅读更多

文章原创于本人博客,http://irfen.me/

一、相关概念

基本回收算法

  • 引用计数( Reference Counting  
    比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为 0 的对象。此算法最致命的是无法处理循环引用的问题。
  • 标记 - 清除( Mark-Sweep  
    此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。
  • 复制( Copying  
    此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。次算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不过出现 ” 碎片 ” 问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间。
  • 标记 - 整理( Mark-Compact  
    此算法结合了 ” 标记 - 清除 ” 和 ” 复制 ” 两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象 ” 压缩 ” 到堆的其中一块,按顺序排放。此算法避免了 ” 标记 - 清除 ” 的碎片问题,同时也避免了 ” 复制 ” 算法的空间问题。
  • 增量收集( Incremental Collecting  
    实施垃圾回收算法,即:在应用进行的同时进行垃圾回收。不知道什么原因 JDK5.0 中的收集器没有使用这种算法的。
  • 分代( Generational Collecting  
    基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。现在的垃圾回收器(从 J2SE1.2 开始)都是使用此算法的。

分代垃圾回收详述

如上图所示,为 Java 堆中的各代分布。

  • Young (年轻代) 
    年轻代分三个区。一个 Eden 区,两个 Survivor 区。大部分对象在 Eden 区中生成。当 Eden 区满时,还存活的对象将被复制到 Survivor 区(两个中的一个),当这个 Survivor 区满时,此区的存活对象将被复制到另外一个 Survivor 区,当这个 Survivor 去也满了的时候,从第一个 Survivor 区复制过来的并且此时还存活的对象,将被复制 ” 年老区 (Tenured)” 。需要注意, Survivor 的两个区是对称的,没先后关系,所以同一个区中可能同时存在从 Eden 复制过来 对象,和从前一个Survivor 复制过来的对象,而复制到年老区的只有从第一个 Survivor 区过来的对象。而且, Survivor 区总有一个是空的。
  • Tenured (年老代) 
    年老代存放从年轻代存活的对象。一般来说年老代存放的都是生命期较长的对象。
  • Perm (持久代) 
    用于存放静态文件,如今 Java 类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些 class ,例如 Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过 -XX:MaxPermSize= 进行设置。

举个例子:当在程序中生成对象时,正常对象会在年轻代中分配空间,如果是过大的对象也可能会直接在年老代生成(据观测在运行某程序时候每次会生成一个十兆的空间用收发消息,这部分内存就会直接在年老代分配)。年轻代在空间被分配完的时候就会发起内存回收,大部分内存会被回收,一部分幸存的内存会被拷贝至Survivor的from区,经过多次回收以后如果from区内存也分配完毕,就会也发生内存回收然后将剩余的对象拷贝至to区。等到to区也满的时候,就会再次发生内存回收然后把幸存的对象拷贝至年老区。

GC 类型

GC 有两种类型: Scavenge GC  Full GC 

  • Scavenge GC
    一般情况下,当新对象生成,并且在 Eden 申请空间失败时,就好触发 Scavenge GC ,堆 Eden 区域进行 GC ,清除非存活对象,并且把尚且存活的对象移动到Survivor 区。然后整理 Survivor 的两个区。
  • Full GC
    对整个堆进行整理,包括 Young 、 Tenured 和 Perm 。 Full GC 比 Scavenge GC 要慢,因此应该尽可能减少 Full GC 。有如下原因可能导致 Full GC :
  • Tenured 被写满
  • Perm 域被写满
  • System.gc() 被显示调用
  • 上一次 GC 之后 Heap 的各域分配策略动态变化

分代垃圾回收过程演示

 vm-2

vm-3

vm-4

vm-5

二、垃圾回收器

目前的收集器主要有三种:串行收集器、并行收集器、并发收集器 。

  • 串行收集器  

    使用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高。但是,也无法使用多处理器的优势,所以此收集器适合单处理器机器。当然,此收集器也可以用在小数据量( 100M 左右)情况下的多处理器机器上。可以使用 -XX:+UseSerialGC 打开。

  • 并行收集器 
  • 对年轻代进行并行垃圾回收,因此可以减少垃圾回收时间。一般在多线程多处理器机器上使用。使用 -XX:+UseParallelGC. 打开。并行收集器在 J2SE5.0 第六 6 更新上引入,在 Java SE6.0 中进行了增强 – 可以堆年老代进行并行收集。如果年老代不使用并发收集的话,是使用单线程进行垃圾回收,因此会制约扩展能力。使用 -XX:+UseParallelOldGC 打开。
  • 使用 -XX:ParallelGCThreads= 设置并行垃圾回收的线程数。此值可以设置与机器处理器数量相等。
  • 此收集器可以进行如下配置:
    • 最大垃圾回收暂停 : 指定垃圾回收时的最长暂停时间,通过 -XX:MaxGCPauseMillis= 指定。 为毫秒 . 如果指定了此值的话,堆大小和垃圾回收相关参数会进行调整以达到指定值。设定此值可能会减少应用的吞吐量。
    • 吞吐量 : 吞吐量为垃圾回收时间与非垃圾回收时间的比值,通过 -XX:GCTimeRatio= 来设定,公式为 1/  1+N )。例如, -XX:GCTimeRatio=19 时,表示 5% 的时间用于垃圾回收。默认情况为 99 ,即 1% 的时间用于垃圾回收。

 

  • 并发收集器 
    可以保证大部分工作都并发进行(应用不停止),垃圾回收只暂停很少的时间,此收集器适合对响应时间要求比较高的中、大规模应用。使用 -XX:+UseConcMarkSweepGC 打开。

 

  • 并发收集器主要减少年老代的暂停时间,他在应用不停止的情况下使用独立的垃圾回收线程,跟踪可达对象。在每个年老代垃圾回收周期中,在收集初期并发收集器会对整个应用进行简短的暂停,在收集中还会再暂停一次。第二次暂停会比第一次稍长,在此过程中多个线程同时进行垃圾回收工作。
  • 并发收集器使用处理器换来短暂的停顿时间。在一个 N 个处理器的系统上,并发收集部分使用 K/N 个可用处理器进行回收,一般情况下1<=K<=N/4 
  • 在只有一个处理器的主机上使用并发收集器,设置为 incremental mode 模式也可获得较短的停顿时间。
  • 浮动垃圾 :由于在应用运行的同时进行垃圾回收,所以有些垃圾可能在垃圾回收进行完成时产生,这样就造成了 ”Floating Garbage” ,这些垃圾需要在下次垃圾回收周期时才能回收掉。所以,并发收集器一般需要 20% 的预留空间用于这些浮动垃圾。
  • Concurrent Mode Failure :并发收集器在应用运行时进行收集,所以需要保证堆在垃圾回收的这段时间有足够的空间供程序使用,否则,垃圾回收还未完成,堆空间先满了。这种情况下将会发生 ” 并发模式失败 ” ,此时整个应用将会暂停,进行垃圾回收。
  • 启动并发收集器 :因为并发收集在应用运行时进行收集,所以必须保证收集完成之前有足够的内存空间供程序使用,否则会出现 ”Concurrent Mode Failure” 。通过设置 -XX:CMSInitiatingOccupancyFraction= 指定还有多少剩余堆时开始执行并发收集

 

  • 小结
    • 串行处理器: 
      – 适用情况:数据量比较小( 100M 左右);单处理器下并且对响应时间无要求的应用。 
      – 缺点:只能用于小型应用
    • 并行处理器: 
      – 适用情况: ” 对吞吐量有高要求 ” ,多 CPU 、对应用响应时间无要求的中、大型应用。举例:后台处理、科学计算。 
      – 缺点:应用响应时间可能较长
    • 并发处理器: 
      – 适用情况: ” 对响应时间有高要求 ” ,多 CPU 、对应用响应时间有较高要求的中、大型应用。举例: Web 服务器 / 应用服务器、电信交换、集成开发环境。

 

三、常见配置举例

  • 堆大小设置 
    JVM 中最大堆大小有三方面限制:相关操作系统的数据模型( 32-bt 还是 64-bit )限制;系统的可用虚拟内存限制;系统的可用物理内存限制。 32 位系统下,一般限制在 1.5G~2G ; 64 为操作系统对内存无限制。我在 Windows Server 2003 系统, 3.5G 物理内存, JDK5.0 下测试,最大可设置为 1478m 。
    典型设置:
  • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
    -Xmx3550m :设置 JVM 最大可用内存为 3550M  
    -Xms3550m :设置 JVM 促使内存为 3550m 。此值可以设置与 -Xmx 相同,以避免每次垃圾回收完成后 JVM 重新分配内存。 
    -Xmn2g :设置年轻代大小为 2G  整个堆大小 = 年轻代大小 年老代大小 持久代大小 。持久代一般固定大小为 64m ,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大, Sun 官方推荐配置为整个堆的 3/8  
    -Xss128k :设置每个线程的堆栈大小。 JDK5.0 以后每个线程堆栈大小为 1M ,以前每个线程堆栈大小为 256K 。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在 3000~5000 左右。
  • java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
    -XX:NewRatio=4: 设置年轻代(包括 Eden 和两个 Survivor 区)与年老代的比值(除去持久代)。设置为 4 ,则年轻代与年老代所占比值为 1  4 ,年轻代占整个堆栈的 1/5
    -XX:SurvivorRatio=4 :设置年轻代中 Eden 区与 Survivor 区的大小比值。设置为 4 ,则两个 Survivor 区与一个 Eden 区的比值为 2:4,一个 Survivor 区占整个年轻代的 1/6
    -XX:MaxPermSize=16m : 设置持久代大小为 16m  
    -XX:MaxTenuringThreshold=0 :设置垃圾最大年龄。 如果设置为 0 的话,则年轻代对象不经过 Survivor 区,直接进入年老代 。对于年老代比较多的应用,可以提高效率。 如果将此值设置为一个较大值,则年轻代对象会在 Survivor 区进行多次复制,这样可以增加对象再年轻代的存活时间 ,增加在年轻代即被回收的概论。

 

  • 回收器选择 
    JVM 给了三种选择:串行收集器、并行收集器、并发收集器 ,但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。默认情况下, JDK5.0 以前都是使用串行收集器,如果想使用其他收集器需要在启动时加入相应参数。 JDK5.0 以后, JVM 会根据当前 系统配置 进行判断。

 

 

 

 

 

 

 

   

四、调优总结

   

五、参考文献

文章原创于本人博客,http://irfen.me/

0
0
分享到:
评论

相关推荐

    java虚拟机垃圾回收详解.docx

    本书主要讲解了java虚拟机垃圾回收机制,垃圾回收器以及java虚拟机的常用配置; Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布。它是Java程序的技术基础,这些程序包括:实用程序、游戏、商业应用...

    java虚拟机垃圾回收详解

    主要讲解了java虚拟机垃圾回收机制,垃圾回收器以及java虚拟机的常用配置

    老生常谈Java虚拟机垃圾回收机制(必看篇)

    下面小编就为大家带来一篇老生常谈Java虚拟机垃圾回收机制(必看篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    JVM虚拟机垃圾回收机制图谱说明

    JVM虚拟机垃圾回收机制图谱说明

    论文研究-嵌入式Java虚拟机的垃圾回收算法的研究 .pdf

    嵌入式Java虚拟机的垃圾回收算法的研究,刘健培,,在嵌入式系统中,需要分析什么样的垃圾回收机制能够适应嵌入式系统的特点,满足系统对于稳定性和性能的要求。本文阐述了嵌入式Jav

    21天学会Java之(Java SE第四篇):Java虚拟机、垃圾回收机制

    文章目录Java虚拟机(JVM)JVM的基本结构类加载机制类的生命周期类加载器的种类类加载机制运行时数据区(内存分析)垃圾回收机制新生代(Young Generation)老年代(Old Generation)元空间(Meta Space) Java虚拟机...

    Java性能调优--关于垃圾回收机制的分析和指导

    关于Java垃圾回收机制的分析已经如何针对Java虚拟机来做应用程序的调优,很详细

    java虚拟机详细解析

    关于java虚拟机的详细解析,从内存分析到垃圾回收算法,hotspot虚拟机回收机制的详细分析,欢迎下载!

    谈谈你对垃圾回收机制的了解?.docx

    一, 垃圾回收机制 在系统运行过程中会产生一些无用的对象,这些对象一直占用内存,不清理这些无用的对象可能会导致内存耗尽,所有垃圾回收机制的是内存. 垃圾收集的原理和概念 对于对象实例收集.主要有两种基本算法,...

    Java高级面试JVM虚拟机、内存结构、垃圾回收机制

    java工程师高级面试之JVM虚拟机底层原理篇:VM种类,内存结构,运行原理,垃圾回收算法,各种垃圾回收器等。

    深入java虚拟机第二版

    第5-20章深入介绍了java的内部细节,垃圾回收、java安全模型、java的连接模型和动态扩张机制,class文件,运算及流程控制。 本书以利于理解的方式深入解释了java虚拟机的内部原理,深入理解这些内容,将对读者更...

    java-jvm虚拟机原理.ppt

    详细介绍了jvm生命周期和体系结构及垃圾回收机制

    java虚拟机知识点整理

    自己看书整理的 java虚拟机精品知识点 java内存区域与内存溢出处理 虚拟机栈和本地方法栈区别 对象定位访问 垃圾收集器GC管理 虚拟机GC垃圾回收收集算法(内存回收方法论) 虚拟机GC垃圾回收收集器(内存回收具体实现...

    Java 虚拟机学习笔记:Java 内存区域,垃圾收集,内存分配与回收策略,JVM 调优,文件结构,类加载机制,Java 程序

    它采用了“一次编写,到处运行”的原则,即一次编写的程序可以在不同的操作系统上运行,这得益于Java虚拟机(JVM)的存在。JVM是Java的核心组成部分,它可以将Java代码解释成特定平台上的机器码,从而实现跨平台运行...

    简单介绍Java垃圾回收机制

    主要介绍了简单介绍Java垃圾回收机制,涉及一些相关的Java术语,Hotspot虚拟机,jvm体系结构等内容,具有一定借鉴价值,需要的朋友可以参考下。

    JVM虚拟机,经典java虚拟机

    JVM虚拟机,经典java虚拟机,了解java的运行机制及详细内存分配和垃圾回收

    深入理解Java虚拟机精华知识点

    从架构角度来看,Java虚拟机主要包括类加载器、运行时数据区、执行引擎、垃圾收集器等部分。类加载器负责将字节码文件加载到内存中,运行时数据区用于存储程序执行时所需的数据,执行引擎则负责执行字节码文件,而...

    jvm垃圾回收思维导图

    圾回收(Garbage Collection)是Java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制。该思维导图完整的描述了垃圾回收的各个关键点

    JVM-Java虚拟机

    资源概要:JVM基础知识;类加载子系统;运行时数据区;对象的创建流程与内存分配;...从广义上讲Java,Kotlin、Clojure、JRuby、Groovy等运行于Java虚拟机上的编程语言及其相关的程序都属于Java技术体系中的一员。

Global site tag (gtag.js) - Google Analytics