`
jianfulove
  • 浏览: 119645 次
  • 性别: Icon_minigender_1
  • 来自: 湛江
社区版块
存档分类
最新评论

JAVA GC垃圾收集器的分析

    博客分类:
  • JVM
阅读更多

在 很多人看来,java中内存的动态分配与内存回收已经不用用户担心了,因为它给我们提供了GC自动回收 ,感觉一切都进入了自动化了,但是对于各种内存溢出,内存泄漏问题的出现,我们还是很有必要学习GC的。地球人都知道,Java有个东西叫垃圾收集器,它 让创建的对象不需要像C/C++那样delete、free掉,但你能不能谈谈,GC是在什么时候,对什么东西,做了什么事情?”  如果还不是很了解那我们一起来学习吧。有目的地去学习GC你就不会觉得枯燥,从头到尾,带着“When” "What" "How" 这个疑问去学习,你的思路会很清晰。

一:要想知道GC到底在什么时候开始工作,必须要先了解垃圾回收器是作用在哪一个区域,采用什么样的内存回收的方式,这种方式设计的GC中采用哪些算法,因此这些问题都要先一一详细说明。

 1、 先来说GC工作在哪块区域呢?根据JVM运行的内存数据区域下画分,如下图。其实GC是工作在方法区和堆区。程序计数器,虚拟机栈(也就平时所说的栈), 本地方法栈这三区域随着线程而生,随着线程而灭,出栈入栈的操作,在栈中分配配的多少内存都具有确定性,在这几个区域就不用考虑回收问题了,因为方法结束 或线程结束,内存自然就回收了。而堆区和方法区都是线程共享,堆区主要存放对象实例及数组对象,方法区存储已加载的类信息(每个类都有唯一个 Class<?>类对应着)、常量、静态变量等,所以只有在程序运行的时候我们才能知道要创建哪些对象,这部分内存的分配和回收都是动态的, 所以这是就GC关注的区域也是它工作的区域。


 

 2、 就拿现在为java已经实现的JVM中的GC是采用哪种内存回收方式呢?实际有很多种内存回收方式,实现垃圾回收时总会综合使用多种设计方式, 会针对不同的情况采用不同的垃圾回收实现。不同方式设计基础也就是基于不同的算法,垃圾收集又有哪些的算法呢?下面分别说明:

   (1)复制算法:将可用内存容量划分为大小相等的两块,每次只使用其中的一块,当这块内存用完了,就要将活着的对象(从根(GC Roots)开始访问每一个关联可到达的对象)复制到另外一块空间上,然后再把已使用的内存空间一次清理掉。如下图:

 

 

 

 (2)标记-清除算法:首先标记出所有需要回收的对象,在标记完成后统一回收所有地被标记的对象。如下图:

 

(3)标记-整理算法:和标记-清除算差不多,首先标记出所有需要回收的对象,先不直接回收不可达对象,而是让所有地存活的对象都向一端移动  然后再清理掉边界以外的内存空间,如下图:

 

 (4)分代收集算法:这个很简单,根据对象的存活周期的不同将内存划分为几块。

 

 

 

3、现行的垃圾回收器用分代的方式来采用不同的回收设计。根据对象生存时间的长短,把堆内存分 成3个代。Young(年轻代),Old(老年代),Permanent(永久代)。


Young:主要是用来存放新生的对象。
Old:主要存放应用程序中生命周期长的内存对象。
Permanent:是指内存的永久保存区域,.它和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理。

 

  其实在JVM中对于垃圾回收时不论采用哪种算法机制来设计垃圾回收器,都会利弊参半,因此实际上实现垃圾回收时总会综合使用多种设计方式也就是基于多种算法的一个综合应用。java现行JVM中基于不同代的特点之上采用不同的回收算法,从而充分利用种回收算法的优点。

 

   首先提前了解下(Minor GC),(Major GC  / Full GC)

GC(Minor GC):指发生在新生代的垃圾收集动作,它不会导致老年代里进行垃圾收集动作发生,因为 Java 对象大多都具备朝生夕灭的特性,所以 Minor GC 非常频繁,一般回收速度也比较快。
GC(Major GC  / Full GC):指发生在老年代的 GC,出现了 Major GC,经常会伴随至少一次的 Minor GC(但非绝对的,在 ParallelScavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程) 。MajorGC 的速度一般会比 Minor GC 慢 10 倍以上。

 

再看上图:划分了不同代后,由于GC主要是发生在对象经常消亡的新生代,如有IBM 的专门研究表明,新生代中的对象98%是朝生夕死的,复制算法实现简单,运行高效,对于复制量不是很大的情况下使用比较合理。所以现在商业虚拟机都采用复 制算法来回收新生代。再看新生代内划分为三个小块。因为新对象经过一次GC后存活下来的就会很少了,不需要按照1:1的比例来划分内存空间,而是设计成将 内存分为一块较大的Eden空间各两块较小的Survivor空间(这两个Survivor空间就是Survivor space:From Survivor或To Survivor。这两个Survivor空间是一样大小的。例如,新生代大小是10M(Xmn10M),那么缺省情况下 (-XX:SurvivorRatio=8),Eden Space 是8M,From和To都是1M。),每次使用Eden和其中的一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地 拷贝到另一块Survivor空间上(如果此时Survivor空间不足怎么办,请看下面),最后清理掉Eden各刚才用过的Survivor的空间。

当 new一个对象时,先在Eden Space上分配,如果Eden Space没有足够的内存空间了,此时就要做一次Minor GC。Minor GC后,要把Eden和From中仍然活着的对象们复制到To空间中去。一般,虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在 Eden 出生并经过第一次 Minor GC 后仍然存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为 1。对象在 Survivor 区中每熬过一次 Minor GC,年龄就增加 1 岁,当它的年龄增加到一定程度(默认为 15 岁)时,就会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。

说到这可以说明(如果此时Survivor空间不足怎么办) 这个问题了,不用担心在发生 Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,改为直接进行一次Full GC  ,如果小于,说明老年代空间还有足够的空间,则要查看设置参数HandlePromotionFailure是否为true,如果是那只会完成这一次 Minor GC,GC后的新生代中活下来并符合老年代条件的对象就被promote到老年代空间,还有To Survivor空间不能容纳下Minor GC后活着的某个对象也会被promote到老年代空间,还有另一种情况就是如果新进来的一个大对象,Eden也没有足够空间存放的时也会直接把它 promote到老年代空间 ;如果false 则也要改为直接进行一次Fulll GC。对于参数HandlePromotionFailure它是指在Survivor轮换备份的过程中,Survivor无法容纳的对象是否直接进入老 年代。谈到怎么进入老年代,顺便说下另一种情况,并不是所有要进入老年代区域的对象年龄必须达到:MaxTenuringThreshold设定的值的, 如果Survivor空间中相同age(例如,age=5)对象的所占内存空间总和大于等于Survivor空间的一半,那么age>=5的对象在 下一次Minor GC后就可以直接promote到老年代,而不用等到age增长到阈值。

  说到这里,再在已经能对GC到底在什么时候开始工作这个问题做个总结了:当在new 对象时,首先考虑在Eden Space上分配内存,如果Eden满了则 进行minor gc,晋升到老年代的对象大于老年代剩余空间full gc,或者小于时被HandlePromotionFailure参数强制full gc;

 

 

 二,对什么东西进行GC呢?

    想知道对什么东西,则就要了解java是如何去判定一个对象是否还存活的。这里它的实现要用到根搜索算法(GC Roots Tracing) 基本意思就是通过一系列名为“ GC Roots”的对象作为起点,从这些节点向下开始进行搜索,搜索所经过的路径称为引用链,当一个对象到GC  Roots 没有任何引用链时相连(说白了就是从GC Roots到这个对象不可达时),则证明此对象是不可用的。
下图中,对象Object6、Object7、Object8虽然互相引用,但他们的GC Roots是不可到达的,所以它们将会被判定为是可回收的对象。

       


 

可作为GC Roots 的对象包括:

 

      1、虚拟机栈(栈帧中的本地变量表)中的引用对象。


      2、 方法区中的类静态属性引用的对象

      3、  方法区中的常量引用的对象

      4、  本地方法栈中JNI的引用对象。

 

 

 

   在根搜索算法中不可到达的对象,也并非 是“真正的死”,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行根搜索后发现没有与GC Roots相连接的引用链,那它将被第一次标记,并且进行一次筛选,筛选条件是此对象是否有必要执行finalize()方法、当对象没有重写 finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行 finalize()”,finalize()方法是对象逃脱死亡命运的最后一次机会了,如果finalize()方法中没有重新与引用链上的任何一个对 象建立关联,说明这个对象不可能复活了,则进行第二次标记,则这个对象真正要被GC清理掉了。

 分析到这里,对于什么东西这个问题也能回答了:从root搜索不可到达的对象,而且经过第一次标记、清理后,仍然没有复活的对象。

 

 

四.做了什么事情,就剩下这个问题了,回答这个问题的空间非常大。

也非常有必要了解不同厂商,不同版本的虚拟机提供的垃圾收集器的实现,了解串行回收器,并行回收器,并行整理回收器,并发标志-清理(CMS)回收器,它们的具体实现,其实这些回收器的实现也是基于前面说过那几种收集算法。

 可以去查看相关的书集,如《深入理解JVM》,这里不一一分析了。

所 以问及GC做了什么事情,答的空间很大,可以说清楚新生代做的是复制清理、from survivor、to survivor是干啥用的、老年代做的是标记清理、标记清理后碎片要不要整理、复制清理和标记清理有有什么优劣势,串行、并行(整理/不整理碎片)、 CMS等搜集器可作用的年代、特点、优劣势等。

 

 

10
2
分享到:
评论
2 楼 charice59 2013-04-02  
楼主分析的很透彻啊,看了之后,有如恍然大悟的感觉,有时间一定要看看《深入理解JVM》这本书。
1 楼 wawxy2009 2013-03-24  
辛苦了,分析的很详细

相关推荐

    Java的垃圾收集器(GC)

    ### Java的垃圾收集器(GC)详解 #### 引言 垃圾收集器(Garbage Collector,简称GC)是Java语言的一项重要特性,它自动化管理内存,显著减轻了开发者手动管理内存负担,避免了常见的内存泄漏问题,提高了程序的...

    Java垃圾收集器使用小诀窍

    Java垃圾收集器使用小诀窍详解 Java垃圾收集器是Java虚拟机(JVM)中一个非常重要的组件,它负责管理Java程序中的内存资源,防止内存泄露和溢出。垃圾收集器的使用小诀窍可以帮助开发者写出高效的Java程序,避免...

    Java的垃圾收集器(GC)整理.pdf

    Java的垃圾收集器(Garbage Collector,简称GC)是Java平台的一个重要特性,它负责自动管理程序中的内存,避免手动内存管理可能导致的内存泄漏问题。Java的垃圾收集机制是基于引用计数和可达性分析算法的,其目标是...

    Java的垃圾收集器(GC)可用.pdf

    Java的垃圾收集器(Garbage Collector,简称GC)是Java编程语言中的一项核心功能,它负责自动管理程序运行过程中的内存分配和释放,极大地简化了程序员的工作。垃圾收集器的引入旨在防止内存泄漏和提高内存利用率,...

    Java的垃圾收集器(GC)参考.pdf

    Java的垃圾收集器(GC)是Java编程语言的一个核心特性,它自动化地管理程序的内存分配和回收,显著减轻了程序员手动管理内存的负担。在Java中,内存管理主要是通过垃圾收集器来实现的,它负责检测并回收不再使用的...

    漫谈Java垃圾收集器.pdf

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

    GC垃圾收集器.xmind

    GC垃圾收集器+GC垃圾收集算法,配合java虚拟机一起看,效果更佳,内容简洁,重要,应届小白面试必备技能

    Java_GC垃圾回收调优指南

    - 并行垃圾收集器(-XX:+UseParallelGC) - 初始堆大小为物理内存的1/64(-Xms) - 最大堆大小为物理内存的1/4(-Xmx,最大1GB) 2. **堆大小调整**: - 即使Ergonomics极大地提升了开箱即用的应用程序体验,但...

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

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

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

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

    Java垃圾收集器参考.pdf

    Java垃圾收集器是Java语言的核心特性之一,它自动化地处理内存管理,使得程序员无需手动回收内存,从而减少了潜在的内存泄漏问题。Java虚拟机(JVM)中的垃圾收集器通过一个低优先级的线程——垃圾收集器线程来监控...

    Java垃圾收集器推荐.pdf

    Java垃圾收集器是Java语言的重要特性,它负责自动管理程序中的内存空间,避免手动内存管理带来的问题,如内存泄漏。垃圾收集器通过一个系统级的线程——垃圾收集线程来工作,它会在Java虚拟机(JVM)空闲时检查并...

    Java理解G1垃圾收集器.pdf

    Java的G1(Garbage First)垃圾收集器是一种先进的垃圾回收机制,主要设计目标是实现低延迟、高吞吐量的内存管理。G1垃圾收集器是Java虚拟机(JVM)的一部分,它引入了区域(Region)的概念,将堆内存划分为多个固定...

    Java垃圾收集必备手册

    在 Java 语言中,垃圾收集器的实现可以分为 serial GC、parallel GC 和 concurrent mark-and-sweep GC 等几种方式。 垃圾收集优化 垃圾收集优化是指对垃圾收集器的优化,以提高垃圾收集的效率和性能。垃圾收集优化...

    Java垃圾收集器知识.pdf

    Java垃圾收集器是Java编程语言的核心特性之一,它自动化地管理程序的内存空间,极大地简化了内存管理的工作,避免了手动回收内存可能导致的错误和内存泄漏问题。以下是对Java垃圾收集器的详细解析: 1. **工作原理*...

    java虚拟机中的垃圾收集GC.pdf

    本篇内容将深入探讨Java虚拟机中的垃圾收集机制,包括不同类型的垃圾收集器、其工作原理以及如何选择合适的垃圾收集器以满足特定应用的需求。 #### 垃圾收集的新发展 近年来,随着计算机硬件的发展和技术的进步,...

    GCViewer,Tagtraum Industries的GCviewer之叉。tagtraum在2008年停止了开发,我的目标是改进对sun/oracle的java 1.6+垃圾收集器日志(包括g1收集器)的支持。.zip

    GCViewer是一款用于分析Java应用程序垃圾收集(Garbage Collection, GC)日志的开源工具,源自Tagtraum Industries的项目,并且在原作者停止开发后由其他人接手并继续更新,以支持Sun/Oracle Java 1.6及更高版本的...

    JAVA垃圾收集.ppt

    java 垃圾整理收集 1垃圾收集器如何做 2垃圾的基本要求

    Java GC的过程

    总结,Java GC的过程涉及内存的自动管理,包括对象的可达性分析、垃圾收集器的选择、GC过程的执行以及调优策略。理解这些概念对于优化Java应用的性能至关重要。在实际开发中,我们需要根据应用的特性和需求来选择...

    java jstat 查看哪个进程频繁GC垃圾回收

    可以通过调整`-Xms`和`-Xmx`(初始堆大小和最大堆大小),或者使用合适的垃圾收集器(如G1或ZGC)来改善。 `Young GC`主要处理年轻代中的对象。如果`Young GC`频繁,可能是新生代设置太小,导致对象快速晋升到老...

Global site tag (gtag.js) - Google Analytics