在日常的运维工作中用到tomcat,都需要对tomcat中的jvm虚拟机进行优化,只有知道需要优化参数的具体用处,才能深刻体会优化jvm的意义所在。

在平常的工作中我们谈对jvm的优化,主要是针对java的堆内存的优化和垃圾回收机制的优化。

JVM堆内存示意图:

    jvm堆内存优化详解_第1张图片    

JVM的堆内存的组成:

  young generation:新生代

   eden:伊甸园区

   surived:存活区

   其中存活区有2个,第1个为S0,第2个为S1

  old generation:老年代   

  permanent generation:持久代

堆内存相关参数详解:

  -Xms:初始化堆内存大小,不包括持久代的内存,默认为物理内存的1/64,不会超过1G

  -Xmx:最大堆内存大小,不包括持久代内存,默认为物理内存的1/4

  -Xmn:新生代内存大小,默认值为Xmx的3/8,老年代内存则为5/8

  -XX:NewRatio:指定新生代与老生代的内存的比值,默认值为2

  -XX:SurvivorRatio:eden和2个存活区内存的比值,默认值为8

  -XX:PermSize:初始化时持久代内存的大小

  -XX:MaxPermSize:最大持久代内存的大小

  建议:

    1.一般建议Xms等于Xmx,好处是避免每次gc后,调整堆的大小,减少系统内存分配开销

    2.建议-XX:PermSize和-XX:MaxPermSize的值相同,因为永久代大小的调整也会导致堆内存需要触发FGC; 一般设置为128M就足够;

栈内存相关参数详解:

  -Xss:指定线程的最大栈空间,默认为1M

jvm垃圾收集算法:

  1.引用计数算法

    每个对象有一个引用计数属性,新增一个引用计数加1,引用释放时计数减1,计数为0可以回收。

    此方法简单,无法解决对象相互循环引用的问题。还有一个问题是如何解决精准计数。

  2.根搜索算法(GC Roots)

    从GC Roots开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链时,则证明此对象是不可用的。

jvm垃圾回收算法:

  1.复制算法(Copying)

  2.标记清除算法(Mark-Sweep)

  3.标记整理压缩算法(Mark-Compac)

  复制算法:

  采用从根集合扫描,并将存活对象复制到一块新的没有使用过的空间中,成本是需要一块内存交换空间

  此算法用于新生代内存回收,从E区复制到S0或者S1

  标记清除算法:

  采用从根集合扫描,对存活的对象标记,标记完毕后再扫描整个空间中未被标记的对象,进行回收。

  优点:在存活对象较多的情况下极为高效

  缺点:标记清除算法直接回收不存活的对象,会造成内存碎片

  标记整理压缩算法:

  采用与标记清除一样的方式进行对象的标记,但在清除时不同,在回收不存活的对象后,会将所有存活

  对象往左端空闲空间移动,并更新对应的指针。此算法在标记清除的基础上,又进行了对象的移动。

  优点:可以解决内存碎片问题

  缺点:成本要比标记清除算法要高

垃圾回收名词解释:

  1.串行回收(Serial)  --> gc单线程内存回收,会暂停所有用户线程,独占式回收

  2.并行回收(Parallel)  --> 多个gc线程并行工作,会暂停所有用户线程,独占式回收

  3.并发回收(CMS) --> gc线程和用户线程同时执行,不需要停顿用户线程(用户线程还是需要停顿,只是很短)

GC串行回收器(Serial回收器):

  1.是一个单线程的收集器,只能使用一个CPU或一条线程去完成垃圾收集;在进行垃圾收集时,必须

     暂停所有其它工作线程。直到收集完成。

  2.缺点:Stop-the-World

  3.优势:简单,对于单CPU的情况,由于没有多线程交互开销,反而更高效。

  开启方法:

    -XX:+UseSerialGC来开启

    使用此参数后:新生代和老年代都采用Serial回收器进行垃圾回收

    新生代使用复制算法

    老年代使用标记压缩算法

GC并行回收器(ParNew回收器):

  1. 并行回收也是独占式回收器,在收集过程中,应用程序会全部暂停。但由于并行回收器使用多线程

   进行垃圾回收,因此在并发能力比较强的CPU上,它产生的停顿时间要短于串行回收器。而在单

   CPU上或者并发能力较弱的系统中,回收效果不会比串行回收器好。

  开启方法:

   -XX:UserParNewGC

   使用此参数后:新生代使用并行回收收集器,老年代使用串行收集器

   -XX:ParallelGCThreads 可以指定线程数量,最好与CPU数量相当

   新生代使用复制算法

新生代吞吐量优先回收器(Parallel Scavenge回收器):

  1.吞吐量优先回收器:关注CPU吞吐量,即运行用户代码的时间/总时间,这种收集器能最高效率利用CPU。

  开启方法:

   -XX:UseParallelGC开启

   使用此参数后:将使用Parallel Scavenge+Serial Old收集器组合回收垃圾,这也是Server模式下的默认值。

   -XX:GCTimeRation 可以设置用户执行时间占总时间的比例,默认为99,即用1%时间进行垃圾收集

   新生代使用复制算法

新生代吞吐量优先回收器(Parallel Scavenge回收器):老生代用Parallel Old算法

  开启方法:

   -XX:UseParallelOldGC开启

   使用Parallel Scavenge和Parallel Old组合收集器进行收集

   老年代使用标记整理算法

并发标记清除回收器(CMS回收器):

  运作过程分为4个阶段:初始标记,并发标记,重新标记,并发清除

  其中标记和重新标记两个阶段仍然需要Stop-The-World,其它过程中收集器和用户线程是一起工作的

  启动方法:

   -XX:ParallelCMSMarkSweepGC

   使用此参数后:使用ParNew + CMS + Serial Old的组合进行内存回收。Serial Old作为CMS出现

   “Concurrent Mode Failure”失败后的后备收集器使用。

  其它参数:

   -XX:ParallelCMSThreads 手工设置CMS的线程数量

   -XX:CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后发出垃圾收集,默认为68%,仅在CMS收集器时有效。

   -XX:CMSFullGCBeforeCompaction:设置CMS收集器在进行若干次垃圾收集后再进行一次内存碎片整理过程,通常与-XX:CMSInitiatingOccupancyFraction一起使用

GC性能监控指标:

  吞吐量 --> 应用花在非GC上的时间百分比

  CG负荷 --> 与吞吐量相反,指应用花在GC上的时间百分比

  暂停时间 --> 应用花在GC stop-the-world的时间

  GC频率 -->

  一个交互式的应用要求暂停时间越少越好,非交互性应用,要求GC负荷越低越好

  一个实时系统对暂停时间和GC负荷的要求都是越低越好