今天遇到一个tomcat服务注册后配置Java参数没效果,最后在注册表中删除原来的tomcat服务后,顺便看了一下tomcat的调优配置,看别人总结的不错,就转载一下。java
Tomcat、Jetty、GlassFish 等等这系列 Web容器/应用服务器,虽然作为容器,提供的是一个 Java Web 的运行时环境,以支持Servlet/JSP 等等这些内容的运行,但咱们都很清楚,其本质上仍是一个 Java 应用程序。 每次对于 容器的启动运行,都是把这个 Java 程序跑起来,来实现 Web 容器的能力。算法
作为一类“特殊”的 Java 应用程序,和任务其余的 Java 应用同样,须要使用到JVM,会有堆,会使用到垃圾回收,会涉及到不一样的堆分区比例... tomcat
所以在对Web 容器( 应用服务器) 的调优中必不可少的是对于 JVM 的调优。服务器
对于 JVM 的调优,主要有两个方面考虑:框架
内存大小配置工具
垃圾回收算法选择测试
固然,确切的说,以上两点并不互相独立,内存的大小配置也会影响垃圾回收的执行效率。优化
其中内存大小配置,最主要作的有spa
肯定内存占用的总大小操作系统
肯定内存中各个代(Gen) 的大小划分
内存大小配置
所谓内存大小的占用,是指应用程序启动后稳定运行一小段时间时,观察到的内存占用状况。
以 HotSpot 虚拟机为例,Java 堆主要有三个空间:
新生代、老年代和永久代。
根据不一样应用的特别,观察应用对于内存的占用,若是有大量的临时对象,不会重复使用,则能够调整 New Gen, 这样这些临时对象就在新生代建立完成,并在 Minor GC 产生时被回收,这样较短生存活的对象不会晋升到老年代,从而能够避免垃圾堆集产生 Full GC。
理想状态下,短时间存活的对象都只在新生代完成生命周期,被费时劲少的
Minor GC 回收完成, 而长期存活,将会屡次使用的在屡次回收以后晋升到老年代, 最终通过 Full GC 完成生命周期。
这里涉及到关于内存大小的调整参数有:
-Xms
-Xmx
这两个参数用于配置 heap 的起始大小和最大值。这里须要通过观察,找一个合适的值,设置太大会致使内存浪费,同时也会致使垃圾回收耗时太长。对于 Tomcat 来讲,通常都会将初始值和最大值设置为相同值,这样就避免在初始内存不足时触发 Full GC 来进行扩展内存。
设定 heap 大小以后,要根据对象生命周期的特征,来调整新生代与老年代的大小比例。
涉及到的参数有:
-XX:NewSize
-XX:NewRatio
-XX:MaxNewSize
-Xmn
第一个是直接设置新生代初始大小,第二个是设置比例(Ratio)。过高或过低都会致使 GC 不能高效的工做。毕竟 Minor GC 也是要耗时的。最后一个设置新生代的初始值和最大值相同,堆空间的变化不影响其值。
对于使用了大量第三方类库的应用来讲,会加载许多框架依赖的类,使用过程当中可能会遇到由于Perm Gen 不足产生的 OOM,这种状况能够经过观察稳定状态下 Perm 区的占用,再经过参数设置。
-XX:PermSize
-XX:MaxPermSize
-XX:MaxMetaspaceSize
第一个会设置Perm区的初始大小,第二个用于设置Perm 区的最大值。在Java 8的时候, Perm 区被移除,改成Metaspace,不过若是遇到相似的OOM,依然能够调整其大小。
此外,对于使用大量线程的应用,也能够配置 -Xss,主要用于设置单个线程的stack 大小。注意,是单个的大小,所以设置值越大,会占用越大,可用的线程数也就越少。
这里的配置通常对于-X开始的能够直接在后面用数字加单位,而-XX的则须要等号后数字再加单位,例如:
java -Xms100m -Xmx200m -XX:PermSize=300m
这里数字后的单能够是m,g,k表明计算机中的不一样单位。
那咱们前面一直在说根据不一样的应用,观察分析设置堆的大小,堆的各个代的大小,那具体观察什么呢?
咱们通常在JVM的配置中增长一些打印 GC 日志的选项,配置方式和上面的相似,这样在 GC 产生时,会打印出各个代占用的大小,具体触发时间等。推荐的配置有如下几个:
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-Xloggc:<文件名>
-XX:PrintGCDateStamps
第一个和第四个选项能够任选一个,第一个打印自JVM启动以来的时间,通常也称为uptime, 第四个打印的是系统当前日期和时间。
根据 GC 日志产生的内容,来观察具体的大小,开始使用上述的配置参数进行调整。固然,也能够用 JConsole, JVisual VM 这些工具可视化的进行了解再调整。工具的使用能够参考历史文章
Java七武器系列多情环 --多功能Profiling工具 JVisual VM
垃圾回收算法
不一样的垃圾回收算法,对于应用的影响很大。一方面可能在一个服务器上却使用了单线程的回收算法,也可能应用对于响应要求很高,但却使用了一个吞吐量优先的算法,致使响应太慢。
因此对于垃圾回收算法的选择,通常都是根据应用的特色,是要低延迟仍是高吞吐量,选择合适的算法。咱们前面也提到,垃圾回收算法和内存的大小配置并不是独立的,内存设置大是回收的频率会下降,但每次的执行时间也会变长。因此这里也是一个须要权衡的地方。
延迟、吞吐量调优
其余 JVM 配置
垃圾回收算法对应到的就是不一样的垃圾收集器,具体到在 JVM 中的配置,是使用 -XX:+UseParallelOldGC 或者 -XX:+UseConcMarkSweepGC 这种不一样的收集器来达到选择算法的目的。
其中 ParallelGC 也称为 吞吐量优先收集器,能够提高应用的吞吐量,但在老年代大小调整之,进行几回垃圾回收后,不能知足应用的低延迟要求。
通常经常使用到ConcMarkSweepGC, 也称之为 CMS GC,其能够作到老年代的垃圾回收与应用程序的纯种并行执行,因此能够实现低延迟。
这里注意,因为 CMS GC 和其余GC回收算法使用的框架不一样,所以不能混用,在使用CMS 进行老年代回收时,新生代默认使用了单线程回收算法,此时能够经过配置 -XX:+UseParNewGC来使用 新生代并行回收。
因为CMS是垃圾回收和应用线程并行,所以须要额外的CPU处理资源,若是只有一个CPU的机器,或者有多个忙碌的CPU,又想要使用低延迟的收集器,此时能够经过配置 CMS 收集器的增量模式来进行回收,经过指定 -XX:+CMSIncrementalMode 来开启增量模式。此时交替运行垃圾收集器应用线程。经过配置
-XX:CMSIncrementalSafetyFactor=X, -XX:CMSIncrementalDutyCycleMin=Y,
-XX:CMSIncrementalPacing 能够控制垃圾收集后台线程为应用线程让出多少CPU周期。
参数-XX:+CMSParallelRemarkEnabled 用来下降标记停顿,另外因为CMS 回收后的老年代内存空间并非连续的,所以经过参数
-XX:+UseCMSCompactAtFullCollection 在Full GC的时候对年老代的压缩。
在JDK1.7 的时候引入了 G1 收集器,能够经过配置-XX:+UseG1GC 来开启。这一方面的实战经验很少,有相关使用经验的朋友欢迎分享。
此外,还能够对新生代进行更细致的配置,好比设置Eden 和 Suvivor 区的比例等,和Newxx相似,能够经过SuvivorRation设置比例。
其余 JVM 配置
可使用 -XX:+DisableExplicitGC 选项来禁止显式的 System.gc 的调用。这个使用时须要评估后再使用。
所谓调优,就是一个不断调整和优化的过程,须要观察、配置、测试再如此重复。有相关经验的朋友欢迎留言补充!
说到底,那上面的这些选项是要配置在哪里呢? 咱们前面提到 Tomcat 本质也是个普通的 Java 应用,所以和通常的 Java 启动方式相似,也是相似
java -Xms100m -XX:+UseParallelOldGC 应用主类
经过这种形式来启动,区别只是 Tomcat 将上述命令放到了文件中,对应到不一样的操做系统,Windows下使用 bat文件, Linux下使用 sh 文件。
因此咱们的配置项也是加到这些文件中。
咱们来看catalina.sh中实际启动时执行的命令:
因此咱们的选项能够加到
JAVA_OPTS
CATALINA_OPTS
这些可选项中。
配置比较简单,例以下面这样:
配置的时候须要特别注意的是,不要把前面已经有的配置冲掉,好比
在配置JAVA_OPTS的时候,要把前面已经配置的加上,写起来是这样:
JAVA_OPTS="$JAVA_OPTS 新增的内容"