在日常的运维工作中用到tomcat,都需要对tomcat中的jvm虚拟机进行优化,只有知道需要优化参数的具体用处,才能深刻体会优化jvm的意义所在。
在平常的工作中我们谈对jvm的优化,主要是针对java的堆内存的优化和垃圾回收机制的优化。
JVM堆内存示意图:
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:指定新生代与老生代的内存的比值
-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负荷的要求都是越低越好