`

浅谈Java中的垃圾回收机制

阅读更多
1.垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾收集算法来实现资源自动回收的功能。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用。
事实上,除了释放没用的对象,垃圾收集也可以清除内存记录碎片。
2.但是任何一种垃圾收集算法一般要做2件基本的事情:(1)发现无用信息对象;(2)回收被无用对象占用的内存空间,使该空间可被程序再次使用。
如何来发现无用的信息对象呢?如何来回收呢?
3.大多数垃圾回收算法使用了根集(root set)这个概念;所谓根集就量正在执行的Java程序可以访问的引用变量的集合(包括局部变量、参数、类变量),程序可以使用引用变量访问对象的属性和调用对象的方法。垃圾收集首选需要确定从根开始哪些是可达的和哪些是不可达的,从根集可达的对象都是活动对象,它们不能作为垃圾被回收,这也包括从根集间接可达的对象。而根集通过任意路径不可达的对象符合垃圾收集的条件,应该被回收。
1、 引用计数法(Reference Counting Collector)

  引用计数法是唯一没有使用根集的垃圾回收的法,该算法使用引用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象(new一个对象)并赋给一个变量时,引用计数器置为 1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用,请问是什么知道这个对象 是不要用了呢?),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。

2、tracing算法(Tracing Collector)

  tracing算法是为了解决引用计数法的问题而提出,它使用了根集的概念。基于tracing算法的垃圾收集器从根集开始扫描,识别出哪些对象可达,哪些对象不可达,并用某种方式标记可达对象,例如对每个可达对象设置一个或多个位。在扫描识别过程中,基于tracing算法的垃圾收集也称为标记和清除(mark-and-sweep)垃圾收集器.

3、compacting算法(Compacting Collector)

  为了解决堆碎片问题,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的过程中,算法将所有的对象移到堆的一端,堆的另一端就变成了一个相邻的空闲内存区,收集器会对它移动的所有对象的所有引用进行更新,使得这些引用在新的位置能识别原来 的对象。在基于Compacting算法的收集器的实现中,一般增加句柄和句柄表。  


分代垃圾回收详述


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

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

GC类型
GC有两种类型:Scavenge GC和Full GC。

   1. Scavenge GC
      一般情况下,当新对象生成,并且在Eden申请空间失败时,就好触发Scavenge GC,堆Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。
   2.

      Full GC
      对整个堆进行整理,包括Young、Tenured和Perm。Full GC比Scavenge GC要慢,因此应该尽可能减少Full GC。有如下原因可能导致Full GC:
          * Tenured被写满
          * Perm域被写满
          * System.gc()被显示调用
          * 上一次GC之后Heap的各域分配策略动态变化

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

   1. 串行收集器

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

      并行收集器
      
         1. 对年轻代进行并行垃圾回收,因此可以减少垃圾回收时间。一般在多线程多处理器机器上使用。使用-XX:+UseParallelGC.打开。并行收集器在J2SE5.0第六6更新上引入,在Java SE6.0中进行了增强--可以堆年老代进行并行收集。如果年老代不使用并发收集的话,是使用单线程进行垃圾回收,因此会制约扩展能力。使用-XX:+UseParallelOldGC打开。
         2. 使用-XX:ParallelGCThreads=<N>设置并行垃圾回收的线程数。此值可以设置与机器处理器数量相等。
         3.

            此收集器可以进行如下配置:
                * 最大垃圾回收暂停:指定垃圾回收时的最长暂停时间,通过-XX:MaxGCPauseMillis=<N>指定。<N>为毫秒.如果指定了此值的话,堆大小和垃圾回收相关参数会进行调整以达到指定值。设定此值可能会减少应用的吞吐量。
                * 吞吐量:吞吐量为垃圾回收时间与非垃圾回收时间的比值,通过-XX:GCTimeRatio=<N>来设定,公式为1/(1+N)。例如,-XX:GCTimeRatio=19时,表示5%的时间用于垃圾回收。默认情况为99,即1%的时间用于垃圾回收。
   3.

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

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


   1.

      堆大小设置
      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区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。


常见配置汇总

   1.

      堆设置
          * -Xms:初始堆大小
          * -Xmx:最大堆大小
          * -XX:NewSize=n:设置年轻代大小
          * -XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
          * -XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
          * -XX:MaxPermSize=n:设置持久代大小


   1.

      收集器设置
          * -XX:+UseSerialGC:设置串行收集器
          * -XX:+UseParallelGC:设置并行收集器
          * -XX:+UseParalledlOldGC:设置并行年老代收集器
          * -XX:+UseConcMarkSweepGC:设置并发收集器


   1.

      垃圾回收统计信息
          * -XX:+PrintGC
          * -XX:+PrintGCDetails
          * -XX:+PrintGCTimeStamps
          * -Xloggc:filename


   1.

      并行收集器设置
          * -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
          * -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
          * -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)


并发收集器设置

    * -XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
    * -XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数
分享到:
评论

相关推荐

    浅谈JAVA垃圾回收机制.pdf

    浅谈 JAVA 垃圾回收机制 Java 垃圾回收机制是 Java 语言中的一种自动内存管理机制,它可以自动回收内存中的垃圾,避免代码运行时由于忘记释放对象而带来的内存泄漏问题。 Java 中的垃圾回收机制主要通过两种算法来...

    关于javal垃圾回收机制的一些文档

    浅谈Java垃圾回收机制.doc文档可能会涵盖以下几个关键点: 1. **对象生命周期**:当一个对象被创建后,它会在内存中占据一定的空间。如果对象不再被任何引用指向,那么这个对象就成为垃圾。 2. **垃圾收集器**:...

    浅谈Java垃圾回收的实现过程

    6. 垃圾回收中实例的终结:垃圾回收中实例的终结在释放一个实例和回收内存空间之前,Java垃圾回收器会调用实例各自的finalize()方法,从而该实例有机会释放所持有的资源。 Java垃圾回收器会根据实例的引用类型来...

    浅谈关于C#的垃圾回收机制

    理解C#垃圾回收机制我们首先说一下CLR(公共语言运行时,Common Language Runtime)它和Java虚拟机一样是一个运行时环境,核心功能包括:内存管理、程序集加载、安全性、异步处理和线程同步。 CTS(Common Type ...

    浅谈Java中的变量.pdf

    Java的垃圾回收机制负责清理不再使用的对象,因此实例变量的生存期可能因多个引用的存在而延长。 5. **Java虚拟机中的内存布局**: JVM在运行时将内存划分为不同的区域,如程序计数器、Java堆、栈、方法区和本地...

    浅谈Java语言评价胜出的8大技术优势

    ### 浅谈Java语言评价胜出的8大技术优势 #### 1. 强大的API支持 Java提供了非常丰富的API支持,包括网络编程中的Socket API、数据库操作中的SQL API、图形用户界面的Swing和AWT API等。这些API不仅功能强大而且...

    浅谈java集合框架

    ### 浅谈Java集合框架 Java集合框架是一个用于存储、操作和检索一组对象的强大工具集。集合框架的设计目的是为了提供一套高效且灵活的数据结构来满足不同的应用需求。本篇文章将详细探讨Java集合框架中的一些核心...

    浅谈JAVA软件开发的几大误区.pdf

    有些开发者认为Java天生慢,但实际上,Java虚拟机(JVM)提供了高效的内存管理和垃圾回收机制。通过合理的内存管理、算法优化以及使用并发处理,可以实现高性能的Java应用。同时,过度优化也可能导致代码可读性和可...

    浅谈Java程序运行机制及错误分析

    浅谈Java程序运行机制及错误分析 Java程序运行机制是指Java虚拟机(JVM)的运行机制和Java程序的执行过程。Java虚拟机是可运行Java代码的假想计算机,以实现Java语言的跨平台特性。Java程序的运行需要经过编写、...

    java培训教程-浅谈java虚拟机.pdf

    4. **无用单元收集堆(Garbage-collected heap)**:Java对象在堆内存中分配,JVM负责自动管理内存,包括对象的创建和销毁,通过无用单元收集(Garbage Collection)机制来回收不再使用的内存,避免内存泄露。...

    浅谈Java堆外内存之突破JVM枷锁

    浅谈Java堆外内存之突破JVM枷锁 本文主要介绍了Java堆外内存的概念,包括JVM内存分配、JVM垃圾回收、堆外内存的垃圾回收等相关内容。Java开发者都知道,Java中不需要手动申请和释放内存,JVM会自动进行垃圾回收;而...

    浅谈计算机软件开发中JAVA编程语言的应用.pdf

    例如,Java虚拟机具有垃圾回收机制,能够自动管理内存,减少了内存泄漏的风险。 Java语言的应用特点之一是其编程程序的独立性。由于其程序运行在虚拟机上,因此可以保证不同阶段(编程、改进、运行)的程序具有相对...

    浅谈计算机软件开发的JAVA编程语言.zip

    Java使用垃圾回收机制自动管理内存,减少了程序员处理内存泄漏的风险。此外,Java采用类作为基本的构造单元,支持多态性和封装,使得代码更加模块化和易于维护。 Java的跨平台能力得益于Java虚拟机(JVM)。JVM允许...

    浅谈关于Java的GC垃圾回收器的一些基本概念

    Java的垃圾回收(GC)是Java虚拟机(JVM)管理内存的重要机制,它自动识别并清理不再使用的对象,以防止内存泄漏。本文主要探讨Java GC的基本概念,涉及JVM内存模型以及不同的垃圾回收算法。 首先,让我们了解几种...

    浅谈jvm中的垃圾回收策略

    Java虚拟机(JVM)中的垃圾回收(Garbage Collection, GC)是自动内存管理的关键机制,它负责识别并清理不再使用的对象,以便回收内存资源。本文将深入探讨JVM的垃圾回收策略,尤其是基于分代的内存回收算法。 在...

    浅谈Java回收对象的标记和对象的二次标记过程

    Java垃圾回收机制是Java语言的一大特性,它负责自动管理程序中的内存,避免程序员手动处理内存分配和释放。本文主要探讨的是对象的标记和二次标记过程,这是垃圾收集器确定对象是否可回收的关键步骤。 一、对象的...

    浅谈Java编程中的内存泄露情况

    本文将深入探讨Java中的内存泄露及其相关的JVM垃圾回收机制。 首先,与C++等语言不同,Java引入了垃圾回收(Garbage Collection, GC)机制,自动负责管理内存,避免程序员手动释放内存可能导致的错误。然而,这并不...

    浅谈Java内存泄露

    在Java中,由于有垃圾回收机制的存在,程序员通常不需要手动管理内存,但并不代表就不会出现内存泄漏。Java的垃圾回收机制主要通过可达性分析来判断对象是否可以被回收,从GC Roots开始遍历引用链,如果一个对象无法...

Global site tag (gtag.js) - Google Analytics