Java虚拟机垃圾收集器分析 基本回收算法 垃圾回收器

Posted 你是我的天晴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java虚拟机垃圾收集器分析 基本回收算法 垃圾回收器相关的知识,希望对你有一定的参考价值。

java虚拟机垃圾收集器分析

1 、活动对象

追踪 root 对象算法: 深度追踪 root 对象,将 heap 中所有被引用到的 root
做标志,所有未被标志的对象视为非活动对象,所占用的空间视为非活动内存。

2 、常用算法

  • Copy 算法

     1  方法:将内存分为两个区域( from space 和 to space )。所有的对象分配内存都分配到 from space 。在清理非活动对象阶段,把所有标志为活动的对象, copy 到 to space ,之后清楚 from space 空间。然后互换 from sapce 和 to space 的身份。既原先的 from space 变成 to sapce ,原先的 to space 变成 from space 。每次清理,重复上述过程。
     
     2  优点: copy 算法不理会非活动对象, copy 数量仅仅取决为活动对象的数量。并且在 copy 的同时,整理了 heap 空间,即, to space 的空间使用始终是连续的,内存使用效率得到提高。
     
     3  缺点:划分 from space 和 to space ,内存的使用率是 1 / 2 。一般在 Young Generation 中使用。
    
  • Compaction 算法

     1  方法:在清理非活动对象阶段,删除非活动对象占用内存,并且把活动对象向 heap 的底部移动,直到所有的活动对象被移到 heap 的一侧。
     
     2  优点:无须划分 from sapce 和 to space ,提高内存的使用率。并且 compaction 后的内存空间也是连续分配的。
     
     3  缺点:该算法相对比较复杂。一般在 Tenured Generation 中使用
    

内存划分

  1. Young Generation

    1  生命周期很短的对象,归为 young generation 。由于生命周期很短,这部分对象在 gc 的时候,很大部分的对象已经成为非活动对象。因此针对 young  generation 的对象,采用 copy 算法,只需要将少量的存活下来的对象 copy 到 to space 。存活的对象数量越少,那么copy 算法的效率越高。
    
    2  young generation 的 gc 称为 minor gc 。经过数次 minor gc ,依旧存活的对象,将被移出 young generation ,移到 tenured generation
    
    3  young generation 分为:
    
    	1  eden :每当对象创建的时候,总是被分配在这个区域
    	
    	2  survivor1 : copy 算法中的 from space
    	
    	3  survivor2 : copy 算法中的 to sapce (备注:其中 survivor1 和 survivor2 的身份在每次 minor gc 后被互换)
    	
    	4  minor gc 的时候,会把 eden+survivor1(2) 的对象 copy 到 survivor2(1) 去。
    
  2. Tenured Generation

    1  生命周期较长的对象,归入到 tenured generation 。一般是经过多次 minor gc ,还 依旧存活的对象,将移入到 tenured generation 。(当然,在 minor gc 中如果存活的对象的超过 survivor 的容量,放不下的对象会直接移入到 tenured generation )
    
    2  tenured generation 的 gc 称为 major gc ,就是通常说的 full gc 。
    
    3  采用 compactiion 算法。由于 tenured generaion 区域比较大,而且通常对象生命周期都比较常, compaction 需要一定时间。所以这部分的 gc 时间比较长。
    
    4  minor gc 可能引发 full gc 。当 eden + from space 的空间大于 tenured generation 区的剩余空间时,会引发 full gc 。这是悲观算法,要确保 eden + from space 的对象如果都存活,必须有足够的 tenured generation 空间存放这些对象。
    
  3. Permanet Generation

    1  该区域比较稳定,主要用于存放 classloader 信息,比如类信息和 method 信息。
    
    2 对于 spring hibernate 这些需要动态类型支持的框架,这个区域需要足够的空间。
    

算法补充:

引用计数(Reference Counting)

比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。

标记-清除(Mark-Sweep)

此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。

复制(Copying)

此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外 一个区域中。次算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不过出现“碎片”问题。当然,此算法的缺 点也是很明显的,就是需要两倍内存空间。

标记-整理(Mark-Compact)

此算法结合了“标记-清除”和“复制”两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历 整个堆,把清除未标记对象并且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问 题。

增量收集(Incremental Collecting)

实施垃圾回收算法,即:在应用进行的同时进行垃圾回收。不知道什么原因JDK5.0中的收集器没有使用这种算法的。

分代(Generational Collecting)

基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。现在的垃圾回收器(从J2SE1.2开始)都是使用此算法的。

垃圾回收器

垃圾回收器选择

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

  • 串行收集器

-XX:+UseSerialGC:设置串行收集器。
并行收集器(吞吐量优先)
-XX:+UseParallelGC:设置为并行收集器。此配置仅对年轻代有效。即年轻代使用并行收集,而年老代仍使用串行收集。
-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时有多少个线程一起进行垃圾回收。此值建议配置与CPU数目相等。
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0开始支持对年老代并行收集。
-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间(单位毫秒)。如果无法满足此时间,JVM会自动调整年轻代大小,以满足此时间。
-XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动调整年轻代Eden区大小和Survivor区大小的比例,以达成目标系统规定的最低响应时间或者收集频率等指标。此参数建议在使用并行收集器时,一直打开。

  • 并发收集器(响应时间优先)

-XX:+UseConcMarkSweepGC:即CMS收集,设置年老代为并发收集。CMS收集是JDK1.4后期版本开始引入的新GC算法。它的主要适合场景是对响应时间的重要性需求大于对吞吐量的需求,能够承受垃圾回收线程和应用线程共享CPU资源,并且应用中存在比较多的长生命周期对象。CMS收集的目标是尽量减少应用的暂停时间,减少Full GC发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代内存。
-XX:+UseParNewGC:设置年轻代为并发收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此参数。
-XX:CMSFullGCsBeforeCompaction=0:由于并发收集器不对内存空间进行压缩和整理,所以运行一段时间并行收集以后会产生内存碎片,内存使用效率降低。此参数设置运行0次Full GC后对内存空间进行压缩和整理,即每次Full GC后立刻开始压缩和整理内存。
-XX:+UseCMSCompactAtFullCollection:打开内存空间的压缩和整理,在Full GC后执行。可能会影响性能,但可以消除内存碎片。
-XX:+CMSIncrementalMode:设置为增量收集模式。一般适用于单CPU情况。
-XX:CMSInitiatingOccupancyFraction=70:表示年老代内存空间使用到70%时就开始执行CMS收集,以确保年老代有足够的空间接纳来自年轻代的对象,避免Full GC的发生。
其它垃圾回收参数
-XX:+ScavengeBeforeFullGC:年轻代GC优于Full GC执行。
-XX:-DisableExplicitGC:不响应 System.gc() 代码。
-XX:+UseThreadPriorities:启用本地线程优先级API。即使 java.lang.Thread.setPriority() 生效,不启用则无效。
-XX:SoftRefLRUPolicyMSPerMB=0:软引用对象在最后一次被访问后能存活0毫秒(JVM默认为1000毫秒)。
-XX:TargetSurvivorRatio=90:允许90%的Survivor区被占用(JVM默认为50%)。提高对于Survivor区的使用率。
辅助信息参数设置
-XX:-CITime:打印消耗在JIT编译的时间。
-XX:ErrorFile=./hs_err_pid.log:保存错误日志或数据到指定文件中。
-XX:HeapDumpPath=./java_pid.hprof:指定Dump堆内存时的路径。
-XX:-HeapDumpOnOutOfMemoryError:当首次遭遇内存溢出时Dump出此时的堆内存。
-XX:OnError=";":出现致命ERROR后运行自定义命令。
-XX:OnOutOfMemoryError=";":当首次遭遇内存溢出时执行自定义命令。
-XX:-PrintClassHistogram:按下 Ctrl+Break 后打印堆内存中类实例的柱状信息,同JDK的 jmap -histo 命令。
-XX:-PrintConcurrentLocks:按下 Ctrl+Break 后打印线程栈中并发锁的相关信息,同JDK的 jstack -l 命令。

小结

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

以上是关于Java虚拟机垃圾收集器分析 基本回收算法 垃圾回收器的主要内容,如果未能解决你的问题,请参考以下文章

Java虚拟机垃圾收集器分析 基本回收算法 垃圾回收器

《深入理解Java虚拟机》读后笔记-垃圾收集算法

《深入理解Java虚拟机》读后笔记-垃圾收集算法

Java虚拟机垃圾回收: 7种垃圾收集器(转载)

Java虚拟机四:垃圾回收算法与垃圾收集器

深入理解java虚拟机GC垃圾回收-垃圾收集算法