jvm学习-垃圾收集

如何判断对象是否须要回收

  • 引用计数算法:有引用就+1,引用失效就-1, 这种算法实现简单,判断效率也高,可是它很难解决对象之间的互相引用问题,A引用B,B引用A,可是A、B都没有被使用了,这种算法回收不了。
  • 可达性分析算法:经过一系列的GC ROOTS做为起始点,从这些起始点向下搜索,当一个对象不可达时证实此对象不可用,GC ROOTS对象的种类:虚拟机栈中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用、本地方法栈中引用对象

        无论什么算法都跟引用有关,Java里面有下面四种引用由强到弱:java

  • 强引用:代码中广泛存在,相似Object obj = new Object(); 垃圾回收确定不会回收
  • 软引用:对象还有用,但又不是必须的,系统将要发生内存溢出时回收,SoftReference类实现软引用
  • 弱引用:也是非必须的对象,垃圾收集器下次工做会回收,WeakReference类来实现弱引用
  • 虚引用:最弱的一种关系,彻底不影响对象的生存时间,也没法经过虚引用来取得一个对象实例,为一个对象设置虚引用的惟一目的就是能在这个对象被回收时收到一个系统通知。

收集算法

  • 标记-清除:先标记出须要回收的对象,统一回收被标记的对象,容易产生内存碎片,效率也不高

        

  • 复制:为了解决效率问题,把内存分开, 只是用其中的一部分,垃圾回收的时候把存活下的对象负责到另外一部分,而后把使用过的空间一次性清理掉, 年轻代98%的对象都是须要回收的,因此内存分配的时候不须要1:1,而是分红eden区和两块存活区,每次把eden和一块存活区负责到另外一块存活区,HotSpot虚拟机推荐用8:1,因此一块存活取空闲着只会浪费10%,固然若是存活的对象多于这10%,将直接进入老年代。

        

  • 标记整理:年老代存活对象比例较大,若是用复制算法就会进行较多的复制操做,效率低下,而且复制算法须要浪费一部分空间,因此这种算法不适合年老代,提出另一种算法标记整理,标记部分跟标记清除算法同样,整理阶段是让存活的对象都向一端移动,而后直接清理掉边界之外的内存。

        

  • 分代收集算法:根据对象存活周期不一样将内存分几块,根据每块的特色使用不一样的收集算法

        

垃圾回收器

内存回收的具体实现,用一些线程模型结合上面算法实现了多种垃圾回收器,以下图:算法

       

存在连线能够搭配使用,目前没有万能的回收器,只能组合使用服务器

  • 串行收集serial:工做线程都停下来,一个线程去完成垃圾回收,复制算法
  • serial Old:    同上,年老代使用标记-整理算法

       

  • 并行收集ParNew: serial收集器的多线程版本,其余参数配置回收策略都与serial同样,看上面的连线只有ParNew收集器和serial收集器能跟CMS合用
  • Parallel Scavenge: 采用复制算法,也是并行收集,它更关注如何控制吞吐量,吞吐量=运行用户代码时间/总时间,它更适合后台运算的程序。
  • Parallel Old: Parallel Scavenge老年代版本,采用多线程和标记整理算法

        

  • CMS:CMS偏响应时间Parallel偏吞吐量,过程,

                    初始标记(要停用户线程):标记一下GC Roots能直接关联到的对象
                    并发标记:进行GC Roots Tracing的过程
                    从新标记(停用户线程),修正并发标记期间用户线程继续运做而致使标记产生变更的那一部分对象的标记记录
                    并发清除:基于标记清除算法作的,因此这阶段就是清除,
            耗时最长的是能够与用户线程一块儿运行的并发标记和并发清除阶段。多线程

        

  • G1:它的目标是做为一款服务器的垃圾收集器,所以,它在吞吐量和停顿控制上,预期要优于 CMS 收集器。与 CMS 收集器相比,G1 收集器是基于标记-压缩算法的(使用G1后内存空间不是连续的,由一些Region组成,经过预测要回收的Region来进行部分回收,2-8理论)。所以,它不会产生空间碎片,也没有必要在收集完成后,进行一次独占式的碎片整理工做。G1 收集器还能够进行很是精确的停顿控制。它可让开发人员指定当停顿时长为 M 时,垃圾回收时间不超过 N。

这里的并行、并发的概念:
        并行(parallel):多个线程同时工做,可是用户线程任然处于等待状态
        并发(Concurrent):用户线程与垃圾收集器线程同时执行。并发

理解GC日志

        

[GC、[Full GC表示停顿类型,[DefNew、[Tenured、[Perm是发生区域,这里的区域名称与使用的垃圾收集器密切相关,方括号里面的3324K->152K(3712K)表示GC以前该内存已使用容量->GC以后该内存使用容量(该内存区域总容量),方括号外面的3324K-152K(11904K)表示GC以前Java堆已使用容量->GC以后Java堆使用容量(Java堆总容量),最后0.0025925secs表示该内存区域GC使用时间。优化

垃圾收集器参数

-XX:+<option> 启用选项
-XX:-<option> 不启用选项
-XX:<option>=<number>
-XX:<option>=<string>spa

-XX:+UseSerialGC Jvm运行在Client模式下的默认值,打开此开关后,使用Serial + Serial Old的收集器组合进行内存回收
-XX:+UseParNewGC 打开此开关后,使用ParNew + Serial Old的收集器进行垃圾回收
-XX:+UseConcMarkSweepGC 使用ParNew + CMS +  Serial Old的收集器组合进行内存回收,Serial Old做为CMS出现“Concurrent Mode Failure”失败后的后备收集器使用。
-XX:+UseParallelGC Jvm运行在Server模式下的默认值,打开此开关后,使用Parallel Scavenge +  Serial Old的收集器组合进行回收
-XX:+UseParallelOldGC 使用Parallel Scavenge +  Parallel Old的收集器组合进行回收
-XX:SurvivorRatio 新生代中Eden区域与Survivor区域的容量比值,默认为8,表明Eden:Subrvivor = 8:1
-XX:PretenureSizeThreshold 直接晋升到老年代对象的大小,设置这个参数后,大于这个参数的对象将直接在老年代分配
-XX:MaxTenuringThreshold 晋升到老年代的对象年龄,每次Minor GC以后,年龄就加1,当超过这个参数的值时进入老年代
-XX:UseAdaptiveSizePolicy 动态调整java堆中各个区域的大小以及进入老年代的年龄
-XX:+HandlePromotionFailure 是否容许新生代收集担保,进行一次minor gc后, 另外一块Survivor空间不足时,将直接会在老年代中保留
-XX:ParallelGCThreads 设置并行GC进行内存回收的线程数
-XX:GCTimeRatio GC时间占总时间的比列,默认值为99,即容许1%的GC时间,仅在使用Parallel Scavenge 收集器时有效
-XX:MaxGCPauseMillis 设置GC的最大停顿时间,在Parallel Scavenge 收集器下有效
-XX:CMSInitiatingOccupancyFraction 设置CMS收集器在老年代空间被使用多少后出发垃圾收集,默认值为68%,仅在CMS收集器时有效,-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSCompactAtFullCollection 因为CMS收集器会产生碎片,此参数设置在垃圾收集器后是否须要一次内存碎片整理过程,仅在CMS收集器时有效
-XX:+CMSFullGCBeforeCompaction 设置CMS收集器在进行若干次垃圾收集后再进行一次内存碎片整理过程,一般与UseCMSCompactAtFullCollection参数一块儿使用
-XX:+UseFastAccessorMethods 原始类型优化
-XX:+DisableExplicitGC 是否关闭手动System.gc
-XX:+CMSParallelRemarkEnabled 下降标记停顿
-XX:LargePageSizeInBytes 内存页的大小不可设置过大,会影响Perm的大小,-XX:LargePageSizeInBytes=128m
-XX:+PrintFlagsFinal 可查看jdk参数的默认值
相关文章
相关标签/搜索