`

7、内存管理机制---垃圾收集器(下)

 
阅读更多

         垃圾收集器是垃圾收集算法的具体实现。Java规范对垃圾收集器的实现没有做任何规定,因此不同的虚拟机提供的垃圾收集器可能有很大差异。HotSpot虚拟机1.7版本使用了多种收集器。(HotSpot使用G1的垃圾收集器)


          共有7种作用不不同分代的收集器,其中Serial、ParNew、Parallel Scavenge(并行清除)属于新生代收集器,CMS、Serial Old(MSC) Parallel Old属于老年代收集器,G1可以作用于这两部分。相互连线表示收集器可以搭配使用。

 

 

1、Serial (连续的、串行)收集器

            Serial收集器是最基本、发展历史最为悠久的收集器。在曾经的JDK1.3之前是新生代收集的唯一选择。

            这个收集器是一个单线程的收集器(即只会使用一个CPU或一条收集线程),在它进行垃圾收集的时,必须暂停其他所有的工作线程(Stop The World),直到它收集结束。这个过程是由虚拟机后台发起并自动完成的,对用户不可见的情况下把用户正常的工作线程全部停掉,这对许多应用是无法接受的。

下图展示了Serial / Serial Old收集器的运行过程。



 

为了消除或减少“Stop The World”停顿,从Serial 到Parallel(平行的、并行) 收集器,再到Concurrent Mark Sweep(CMS 并发标记-清除)到Garbage First(G1)收集器,越来越复杂,性能也越来越好,用户停顿时间越来越小。虽然Serial有着这一无法消除的影响,但是它仍旧是虚拟机运行在Client 模式下的默认新生代收集器。在单CPU环境来说,Serial 由于没有线程交互的开销,专心做垃圾收集,因而具有最高的收集效率。在用户的桌面应用中,分配给虚拟机的内存一般不会很大,收集一两百M的新生代所用的停顿时间完全可以控制在一百ms之内。所以,Serial收集器对于运行在Client模式下的虚拟机来说是一个很好地选择。收集器可用的控制参数如下:

-XX:+UserSerialGC 在新生代和老年代使用串行收集器

-XX:+SurvivorRatio 设置eden和survivor区大小的比例

-XX:+PretenureSizeThreshold 直接晋升到年老代的对象大小,设置此参数后,超过该大小的对象直接在年老代中分配内存

-XX:+MaxTenuringThreshold 直接晋升到年老代的对象年龄,每个对象在一次Minor GC之后还存活,则年龄加1,当年龄超过该值时进入年老代

 

2、ParNew收集器

        ParNew 收集器其实就是serial 收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为与Serial收集器一样。但它却是Server模式下的虚拟机中首选的新生代收集器,与性能无关的一个原因是,除了Serial收集器外,只有它能与CMS收集器配合工作,后者是HotSpot 虚拟机中第一款真正意义上的并发(Concurrent)收集器,它第一次实现了让垃圾收集线程与用户线程同时工作。

在多核多线程系统中,使用-XX:ParallelGCThreads参数限制垃圾收集线程数。

ParNew收集器也是使用-XX:+UseConcMarkSweepGC选项后的默认新生代收集器,也可以使用-XX:+UseParNewGC来指定它。

关于垃圾收集中的并发和并行,可以解释如下.

  • 并行(Parallel):指多条垃圾收集线程并行工作,用户线程仍处于等待状态。

  • 并发(Concurrent):指用户线程与垃圾收集线程同时执行,用户程序继续运行,而垃圾收集程序运行在另一个cpu上。

 3、Parallel Scavenge (并发清除)收集器

       Parallel Scavenge收集器也是新生代收集器,使用复制算法,也是并行的多线程收集器,和ParNew 大致一样。但是Parallel Scavenge 的关注点与其他收集器不同,CMS等关注于尽可能缩短用户线程停顿时间,而Parallel Scavenge目标则是达到一个可控制的吞吐量(Throughput)。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗的时间的比值,如虚拟机运行了100分钟,垃圾收集花掉了1分钟,那么吞吐量便是99%。

-XX:+UseParNewGC 打开此开关参数后,使用ParNew+Serial Old收集器组合进行垃圾收集。

-XX:+UseParallelOldGC 打开此开关参数后,使用Parallel Scavenge+Parallel Old收集器组合进行垃圾收集。

-XX:+ParallelGCThreads 设置并行GC时进行内存回收的线程数。

 

-XX:+MaxGCPauseMillis Parallel Scavenge收集器最大GC停顿时间(>0)。

-XX:GCTimeRatio  直接设置吞吐量大小(0-100)。

-XX:+GCTimeRation Parallel Scavenge收集器运行时间占总时间比率。

-XX:+UseAdaptiveSizePolicy java虚拟机动态自适应策略,动态调整年老代对象年龄和各个区域大小。

 

4、Serial Old 收集器jdk1.5

       Serial Old 收集器是Serial 的老年代版本,同样是一个单线程收集器,使用“标记-整理”算法。主要意义也是在Client 模式下使用。

 

5、Parallel Old 收集器jdk1.6

         Parallel Old是Parallel Scavenge 收集器的老年代版本,使用多线程和“标记-整理”算法。

        在它出现之前,由于新生带收集器Paralle Scavenge 只能和Serial Old 配合,老年代Serial Old 收集器是单线程而Paralle Scavenge是多线程,即使使用Parallel Scavenge 收集器也不能在整体应用上获得吞吐量最大化的效果。这种组合甚至不如 ParNew (多线程)+ CMS 的组合给力。直到 Parallel Old的出现。 Parallel Old工作过程如下图。

 

 6、CMS 收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。主要用于互联网或B/S系统的服务端,这类应用尤其重视服务的响应速度。

前面的都是并行收集器,CMS是整体上市并发的(低停顿收集器);

从名字可以看出,CMS是基于“标记-清除”算法的,运作过程更加复杂一些,分为4个步骤:

 

  • ①.初始标记(CMS initial mark)   标记GC Roots直接关联的对象
  • ②.并发标记(CMS concurrenr mark)   可达性分析算法
  • ③.重新标记(CMS remark)  并发变动修改
  • ④.并发清除(CMS concurrent sweep)
其中初始标记、重新标记这两个步骤任然需要停顿其他用户线程。初始标记仅仅只是标记出GC ROOTS能直接关联到的对象,速度很快,并发标记阶段是进行GC ROOTS 根搜索算法阶段,会判定对象是否存活。而重新标记阶段则是为了修正并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间会比初始标记阶段稍长,但比并发标记阶段要短。由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以整体来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。执行过程如下图。
CMS收集器的优点:并发收集、低停顿,但是CMS还远远达不到完美,主要有三个显著缺点:
  • CMS收集器对CPU资源非常敏感。在并发阶段,虽然不会导致用户线程停顿,但是会占用CPU资源而导致引用程序变慢,总吞吐量下降。CMS默认启动的回收线程数是:(CPU数量+3) / 4。
  • CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure“,失败后而导致另一次Full GC的产生。由于CMS并发清理阶段用户线程还在运行,伴随程序的运行自热会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在本次收集中处理它们,只好留待下一次GC时将其清理掉。这一部分垃圾称为“浮动垃圾”。也是由于在垃圾收集阶段用户线程还需要运行,即需要预留足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分内存空间提供并发收集时的程序运作使用。在默认设置下,CMS收集器在老年代使用了68%的空间时就会被激活,也可以通过参数-XX:CMSInitiatingOccupancyFraction的值来提供触发百分比,以降低内存回收次数提高性能。要是CMS运行期间预留的内存无法满足程序其他线程需要,就会出现“Concurrent Mode Failure”失败,这时候虚拟机将启动后备预案:临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。所以说参数-XX:CMSInitiatingOccupancyFraction设置的过高将会很容易导致“Concurrent Mode Failure”失败,性能反而降低。
  • CMS是基于“标记-清除”算法实现的收集器,使用“标记-清除”算法收集后,会产生大量碎片。空间碎片太多时,将会给对象分配带来很多麻烦,比如说大对象,内存空间找不到连续的空间来分配不得不提前触发一次Full GC。为了解决这个问题,CMS收集器提供了一个-XX:UseCMSCompactAtFullCollection开关参数,用于在Full GC之后增加一个碎片整理过程,还可通过-XX:CMSFullGCBeforeCompaction参数设置执行多少次不压缩的Full GC之后,跟着来一次碎片整理过程。

7、G1 收集器jdk1.7

G1 是面向服务端应用的垃圾收集器。具有如下几个特点。

  • 并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短Stop-The-World停顿的时间,其他(除CMS)收集器原本需要停顿Java线程,G1收集器仍然可以通过并发的方式让Java程序继续执行。
  • 分代收集:与其他收集器一样,分代概念在G1中依然得以保留。虽然G1可以不需其他收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。
  • 空间整合:与CMS的“标记-清理”算法不同,G1从整体看来是基于“标记-整理”算法实现的收集器,从局部(两个Region之间)上看是基于“复制”算法实现,无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。
  • 可预测的停顿:这是G1相对于CMS的另外一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器特征了。
        在G1之前的其他收集器进行收集的范围都是新生代和老年代,而G1收集时,java堆的内存布局与其他收集器有很大区别,它将整个java堆划分为多个大小相等的独立区域(region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都属于Region集合。
   G1收集器之所以能建立可预测的停顿时间模型,因为它可以避免全堆内存的垃圾收集(使用Remembered Set避免全堆扫描)。G1跟踪各个Region里面的垃圾堆积的价值大小(回收后会获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回价值最大的Region(这也就是Garbage-First名称的来由)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内获可以获取尽可能高的收集效率。

G1收集器的运作大致可划分为以下几个步骤: 

  • 初始标记(Initial Marking)
  • 并发标记(Concurrent Marking)
  • 最终标记(Final Marking)
  • 筛选回收(Live Data Counting and Evacuation)

$ gc日志:

JVM的GC日志的主要参数包括如下几个:

-XX:+PrintGC 输出GC日志

-XX:+PrintGCDetails 输出GC的详细日志

-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)

-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)

-XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息

-Xloggc:D:/Documents/gc.log 日志文件的输出路径

在eclipse中参数设置中添加:

-XX:+PrintGCDetails  
-XX:+PrintHeapAtGC  
-XX:+PrintGCDateStamps  
-XX:+PrintTenuringDistribution  
-verbose:gc  
-Xloggc:D:/Documents/gc.log
打开文件:
Heap
 def new generation   total 4928K, used 691K [0x248f0000, 0x24e40000, 0x29e40000)
  eden space 4416K,  15% used [0x248f0000, 0x2499cf80, 0x24d40000)
  from space 512K,   0% used [0x24d40000, 0x24d40000, 0x24dc0000)
  to   space 512K,   0% used [0x24dc0000, 0x24dc0000, 0x24e40000)
 tenured generation   total 10944K, used 0K [0x29e40000, 0x2a8f0000, 0x348f0000)
   the space 10944K,   0% used [0x29e40000, 0x29e40000, 0x29e40200, 0x2a8f0000)
 compacting perm gen  total 12288K, used 146K [0x348f0000, 0x354f0000, 0x388f0000)
   the space 12288K,   1% used [0x348f0000, 0x34914b50, 0x34914c00, 0x354f0000)
    ro space 10240K,  45% used [0x388f0000, 0x38d77290, 0x38d77400, 0x392f0000)
    rw space 12288K,  54% used [0x392f0000, 0x3997ace8, 0x3997ae00, 0x39ef0000)

 参看:http://blog.csdn.net/huangzhaoyang2009/article/details/11860757

 

            http://wentao365.iteye.com/blog/1142837

 

  • 大小: 116 KB
  • 大小: 150.2 KB
  • 大小: 180.3 KB
  • 大小: 109.8 KB
  • 大小: 30 KB
  • 大小: 116 KB
分享到:
评论

相关推荐

    C#内存管理机制C#内存管理机制

    此外,C#内存管理机制还可以帮助程序员更好地理解垃圾收集器的工作原理,并避免垃圾收集器带来的性能问题。 C#内存管理机制是C#编程语言中的一种机制,旨在帮助程序员更好地管理内存资源。了解C#内存管理机制可以...

    java内存管理白皮书-英文版

    ### Java内存管理概述 ...为了深入了解Java内存管理和垃圾收集器的工作原理,建议参考Sun Microsystems提供的官方文档和其他技术资源。此外,还可以探索社区论坛和技术博客,获取更多的实践经验和技巧。

    Java的内存管理机制分析

    ### Java的内存管理机制分析 #### 一、Java内存区域划分 Java的内存管理机制将内存分为以下几个区域: 1. **栈(Stack)**: - 存储局部变量(如基本类型的变量和对象的引用)。 - 每个线程拥有一个独立的栈。 ...

    JVM初探- 内存分配、GC原理与垃圾收集器

    JVM内存管理是Java虚拟机的核心机制之一,其主要包含对象的创建、内存分配、...通过对内存分配策略、对象生死判定、垃圾收集算法和垃圾收集器的理解与应用,可以更好地掌握JVM的内存管理,从而提升应用性能和稳定性。

    漫谈Java垃圾收集器.pdf

    Java垃圾收集器是Java虚拟机(JVM)中的一种自动内存管理机制,旨在释放程序员从手动内存管理的繁琐工作中解脱出来。垃圾收集器通过跟踪对象的引用关系,确定哪些对象是可以被释放的,然后将其回收,以避免内存泄露...

    7种JVM垃圾收集器特点-优劣势-及使用场景.pdf

    JVM垃圾收集器是Java虚拟机(JVM)中的一种自动内存管理机制,负责回收Java程序中不再使用的对象,以避免内存泄漏和提高程序性能。Java中有多种垃圾收集器,每种垃圾收集器都有其特点、优劣势和使用场景。 1. ...

    计算机科学与技术-外文翻译-外文文献-英文文献-Java垃圾收集器的工作方式.doc

    总的来说,Java垃圾收集器通过自动化内存管理,既提高了对象创建的效率,又降低了内存管理的复杂性,是Java平台的一大优势。理解垃圾收集的工作机制对于编写高效、健壮的Java应用程序至关重要。开发者可以通过调整...

    NET解密--深入理解.NET垃圾收集机制参照.pdf

    .NET框架提供了几个关键方法来与垃圾收集器交互,如`GC.Collect()`用于强制执行垃圾收集,`GC.WaitForPendingFinalizers()`等待所有终结器执行完毕,`GC.GetTotalMemory(true)`获取应用程序使用的总内存等。...

    JVM-内存管理 2012-12.pdf

    对Java开发人员而言,理解这些内存管理机制不仅能够帮助其编写出更加稳定和高效的代码,还能在发生内存问题时迅速定位和解决问题。随着JDK版本的更新,内存管理的机制和参数也在不断地优化和演进,开发者需要不断...

    Sun_JDK_1.6内存管理--实现篇-毕玄

    它采用了更先进的垃圾收集器,如实时垃圾收集器(Real Time GC),能够在保证低延迟的情况下进行垃圾收集,非常适合对响应时间有严格要求的应用场景。此外,JRockit还提供了更精细的内存管理工具和监控能力,帮助...

    Sun JDK 1.6内存管理--调优篇

    G1是新一代的垃圾收集器,目标是实现可预测的暂停时间模型。 针对内存调优,我们需要关注以下几点: 1. 合理设置堆大小:根据应用的内存需求,设置-Xms和-Xmx参数来控制堆的初始和最大大小,避免因内存不足导致的...

    Java垃圾收集机制解析:自动内存管理的艺术

    本文将深入探讨Java中的垃圾收集机制,包括其工作原理、不同类型的垃圾收集器以及它们在实际应用中的使用。 Java语言的一大卖点是它提供了自动内存管理,这意味着程序员不需要手动分配和释放内存,从而减少了内存...

    垃圾收集机制的基本原理及方法word版

    - **垃圾收集器**:JVM使用不同的垃圾收集器策略,如分代收集、标记-清除、复制、标记-压缩等,来优化内存管理。分代收集将堆分为年轻代和老年代,以适应不同生命周期的对象。 - **可达性分析**:垃圾收集器通过...

    Java垃圾收集必备手册

    Java 垃圾收集是 Java 语言中的一种自动内存管理机制,旨在释放不再使用的内存资源,以避免内存泄漏和提高程序性能。在这篇手册中,我们将深入探究 Java 垃圾收集的基础知识,包括垃圾收集的定义、垃圾收集算法、...

    Java的垃圾收集器(GC)

    总之,垃圾收集器是Java生态系统中不可或缺的一部分,深入理解和合理运用GC机制,对于构建高效、稳定的Java应用程序至关重要。随着Java技术的不断演进,GC也将持续优化,为开发者带来更加便捷的开发体验。

    对象的释放和垃圾收集机制.txt

    在Java等语言中,对象的释放通常由垃圾收集器自动完成,但在C++等语言中,则需要程序员手动进行管理。 ##### Java中的对象释放 Java通过一种名为垃圾收集(Garbage Collection, GC)的机制来管理内存。GC会在适当的...

    如何实现一个垃圾收集器 - 知乎1

    在本文中,我们将探讨如何实现一个简单的垃圾收集器,这是一个基础的自动化内存管理系统,主要针对Java环境。垃圾收集器是现代编程语言运行时系统的关键组件,负责自动管理内存,回收不再使用的对象以避免内存泄漏。...

    c#内存检测工具-----

    同时,理解C#内存管理机制,结合实际的检测结果,有助于编写更高效、资源友好的代码。对于大型或复杂项目,定期进行内存分析和优化是必要的,以确保应用程序在长时间运行后仍能保持良好的性能。

    性能工程师指南:玩转OpenJDK HotSpot垃圾收集器

    5. **内存层面**:特别关注Java虚拟机(JVM)中的内存管理机制,如垃圾收集(GC)过程。 #### 四、Java虚拟机(JVM)性能工程 Java虚拟机(JVM)是运行Java程序的核心组件之一,它负责将Java字节码转换为特定平台的机器...

    1_Java虚拟机(垃圾收集器和算法).pdf

    本文详细探讨了JVM中的垃圾收集器和垃圾收集算法,以帮助开发者深入理解Java虚拟机的内部运作机制。 垃圾收集(GC,Garbage Collection)是JVM的一个重要功能,用于自动释放不再使用的对象所占用的内存空间,以防止...

Global site tag (gtag.js) - Google Analytics