JVM的GC

来源:互联网 发布:网络推广新手 编辑:程序博客网 时间:2024/06/03 16:48

垃圾收集算法

        基于回收策略划分

                引用计数算法

                        对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1,只要对象A的引用计数的值为0,则对象A就不可能再被使用。此算法的问题:引用计数器的维护影响性能;很难处理循环引用。该算法没有被java采用。



                标记-清理算法

                        该算法分为“标记(Mark)”和“清除(Sweep)”两个阶段:首先从引用根节点标记所有被引用的对象,然后将未标记的对象清除。该算法是最基础的收集算法,后续的收集算法都是基于这种思路并对其不足进行改进而得到的。此算法的问题:会产生内存碎片,另外就是标记和清除两个过程的效率都不高。

                                                   


                复制算法

                        把内存划分为两个相等的区域,每次只使用其中一个区域,当垃圾回收时,将当前使用区域中存活对象复制到另一个区域中。此算法每次只处理存活对象,存活对象越少复制成本越小,同时复制过去的同时也进行了内存整理,不会出现“碎片”问题。缺点就是需要两倍内存空间。



                标记-整理算法

                        标记-整理算法也有人称标记-压缩算法,此算法分为两个阶段:首先从根节点开始标记所有被引用对象,然后,清除未标记对象,并且,把存活对象按顺序排放到内存的一端。该算法避免了“标记-清理”的碎片问题,同时也避免了“复制”算法的空间问题。

                                                            


                分代收集算法

                        该算法的思想是将管理的内存按照对象存活周期的不用,分成不同的块(代),一般分为新生代和老年代,每个代可以采用不同的算法进行垃圾回收。

                       新生代中,每次垃圾收集时都会发现大批对象死去,只有少量存活,那就可以选复制算法。由于新生代中的对象一般都是“朝生夕死”,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一个较大的Eden去和两块较小的Survivor区,每次使用Eden和其中一个Survivor,当进行垃圾回收时,将Eden和Survivor1中还存活的对象一次性地复制到Survivor2空间上,最后清理掉Eden和Survivor1空间,注意,如果Survivor2的空间不够用时,则需要依赖老年代进行分配担保,即需要老年代的空间进行存储这些对象,所以,对于HotSpot虚拟机默认Eden和Survivor的大小比例是8:1的设置,我们可以视应具体情况进行调整。

                       年老代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法进行回收。


        基于系统线程划分

                串行收集

                       使用单线程处理所有垃圾回收工作,因为无需多线程交互,实现容易,而且效率比较高。但是,其无法使用多处理器的优势,所以,此收集适合单处理器机器,也可用在小数据量(100M左右)情况下的多处理器机器上。


                并行收集

                        使用多线程处理垃圾回收工作,因而速度快,效率高,而且理论上CPU数目越多,越能体现出并行收集器的优势。


                并发收集

                        相对于串行收集和并行收集而言,前面两个在进行垃圾回收工作时,需要暂停整个运行环境,而只有垃圾回收程序在运行,因此,系统在垃圾回收时会有明显的暂停,而且,暂停时间会因为堆越大而越长。并发收集的目的就是尽所能使垃圾回收程序和应用程序可以同时运行。


垃圾收集器

        概述

                垃圾收集算法是方法论,垃圾收集器是具体的实现,并且,没有规定说垃圾收集器如何实现,因此,不同的厂商、不同版本的虚拟机提供的垃圾收集器可能有很大差别,下面讨论的都是JDK的HotSpot虚拟机的收集器


        串行收集器

                Serial收集器

                         垃圾回收时,应用线程都必须暂停,只能有一个垃圾收集线程在工作,JDK1.3.1之前是虚拟机新生代的唯一选择。

                        -XX:+UseSerialGC:启动Serial收集器,作用在年轻代,年轻代使用复制算法,若老年代没有使用CMS收集器,Serial收集器也会作用于老年代,老年代使用标记-整理算法。Client模式下默认启用的收集就是Serial收集器。



        并行收集器

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


               ParNew收集器

                        ParNew收集器是Serial收集器的多线程版本,使用多线程进行垃圾收集,只作用于年轻代,使用复制算法。有时多线程不一定比单线程快,具体根据硬件配置等情况看。

                        -XX:+UseParNewGC:启用ParNew收集器,此收集器只使年轻代的收集为多线程,其它和Serial收集器的作用一样。


               Parallel和Parallel Old收集器

                        Parallel收集器:只作用于年轻代的收集器,JDK1.4中就已存在,更加关注吞吐量,使用复制算法

                        Parallel Old收集器:只作用于老年代的收集器,JDK1.6中才存在,使用标记-整理算法,和Parallel收集类似。

                        -XX:+UseParallelGC:启用Parallel收集器,只作用于年轻代,若年老代没有使用Parallel收集器,则使用串行收集器

                        -XX:+UseParallelOldGC:启用Parallel Old收集器,并行回收老年代,该回收器只能和Parallel收集器一起使用。

                        -XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。

                        -XX:+UseAdaptiveSizePolicy:参数打开后,手动指定的-Xmn、-XX:SurvivorRatio、-XX:PretenureSizeThreshold等细节参数豆浆实现,并行收集器会自动选择年轻代大小,以及Eden和Survivor的比值,以达到相应的停顿时间或者垃圾收集时间的总占比。


        并发收集器

               CMS收集器

                       ConCurrent Mark Sweep采用标记-清除,作用于老年代,可Serial或ParNew收集器一起使用。优点是并发收集,低停顿。分为四个阶段,具体过程如下图:


                        -XX:+UseConcMarkSweepGC:启用CMS收集器,作用于老年代。

                        -XX:ParallelCMSThreads=4:设置CMS的线程数量。

                        -XX:+UseCMSCompactAtFullCollection:默认是开启的,CMS收集器进行FullGC时,开启内存碎片的合并整理功能,内存整理的过程是无法并发的,空间碎片没有了,但停顿时间会增长。

                        -XX:CMSFullGCsBeforeCompaction=3:默认值为0(每次进入FullGC时都要进行碎片整理),用于设置执行多少次不压缩的FullGC后,跟着来一次碎片整理。

                        -XX:CMSInitiatingOccupancyFraction=80:当老年使用80%的空间后,CMS收集器就会被激活。JDK1.5的默认值为68,JDK1.6的默认值为92。该值的设置一定要合理,不能设置的太高:CMS收集器在进行垃圾收集时,和应用程序一起工作,所以,不能等到老年代几乎完全被填满了再进行收集,这样会影响并发的应用线程的空间使用,会出现Concurrent Mode Failure失败,从而导致老年代启用串行收集器来重新进行老年代的垃圾收集,使应用线程的停顿时间变得更长,性能反而降低。


GC的触发

        Young GC:仅对新生代进行垃圾回收。当新对象生成,并且在Eden申请空间失败时,就会触发Young GC。

        Full GC:对新生代,老年代和持久代都进行垃圾回收。Full GC比Young GC慢的多,因此对JVM调优的过程中,很大一部分工作就是对FullGC的调节。可能导致Full GC的原因:年老代被写满;持久代被写满;System.gc()被显示调用;上次GC之后Heap的各域分配策略动态变化。

原创粉丝点击