之前在网上有看到过很多关于Tomcat启动参数的设置,有不少类似于标准的设置参考,但是很多解释比较模糊,在阅读过《深入理解java虚拟机》一书之后,其中主要涉及的JVM优化想跟大家分享一下,如有错误还请指正。
一般优化就是在catalina.bat或者catalina.sh的首行之前加入JAVA_OPTS="",其中catalina.bat可以不用引号,catalina.sh必须加上引号,否则不生效也没有任何提示。目前我的环境主要是是4G内存的windows server2008和CentOS5.9的64系统,然后是JDK1.7_45的64位虚拟机(也就是HotSpot),tomcat版本为7.0.42。大概是为了实现每秒2000次响应,其中算法和数据库时间都在100ms以下,而且都能够承受如此频率的响应。我的配置开始也是照抄的网上大神们的,后面了解之后稍微做了一些修改如下:
下面介绍以下每一项的意思,可能不是特别全面而且用词可能不是特别准确,主要是根据书中所说进行的简单总结。
1."-server":启动虚拟机运行在server模式下,默认是在client模式下。这两个模式大致有两个方面的区别默认垃圾收集器和编译行为。垃圾收集器,client模式下默认为新生代Serial收集器+老年代Serial Old收集器,首先这两个收集器都是单线程的,既是只会用一个CPU或一条收集线程去完成垃圾收集工作。而且这两个垃圾收集器都会有"Stop The World"的不良用户体验,既是在用户不可见的情况下吧用户正常工作的线程全部停掉,当然新生代还是采取的复制算法,老年代为标记整理算法,如下图
而在server模式下新生代默认采用的Parallel Scavenge收集器,老年代采用的Serial Old收集器(因为没有其他老年代收集器能与Parallel Scavenge收集器配合)。其中Parallel Scavenge收集器是可以达到一个可控的吞吐量的收集器,可以使用配置"-XX:MaxGCPauseMillis"参数和"-XX:GCTimeRatio"参数来指定最长停顿时间和吞吐量大小,吞吐量即是GC时间占总CPU时间的比值,比如将GCTimeRatio配置为19,那么允许的最大GC时间就占总时间的5%(1/(1+19))。
关于编译,HotSpot虚拟机中内置了两个即时编译器,分别为Client Compiler(C1编译器)和Server Compiler(C2编译器),他们都是虚拟机的后端运行期编译器(JIT编译器,Just In Time Compiler)把字节码转变成机器码的过程。因为最初Java程序是通过解释器进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认作”热点代码“(Hot Spot Code),为了提高执行效率,运行时虚拟机会将这些代码编译为与本地平台有关的机器码,并进行各种优化,完成这项任务的编译器就是JIT编译器。大致可以简单的认为C1的编译速度较快,C2的编译质量较高(优化更多),但其实无论在server还是client模式下都可以采用分层编译(Tiered Compilation),其中jdk7的server模式分层编译默认开启。也可以通过"-XX:+TieredCompilation"手动开启。这个参数有助于在程序启动响应速度和运行效率之间达到平衡。server模式和client模式在Hot Spot Code的判定上面也有所不同,判定方法是否为Hot Spot Code见后文关于"-XX: CompileThreshold"参数介绍,在判定代码块(循环语句等)时,server的默认值会比client更宽松,也就是server会做更多的编译工作。在其他方面server模式会进行一些更复杂和激进的编译优化,本人才疏学浅不作介绍,可以参见Sun官方Wiki百科。
2."-Xms2048m":设置JVM堆的最小大小为2048m,一般跟最大大小设置为一样,避免动态分配影响性能。
3."-Xmx2048m":设置JVM堆的最大大小为2048m,需要注意的是本地方法栈、方法区和直接内存都不在这个范围之中,所以需要考虑到这部分内存加上堆内存才是整个应用所使用的内存。而且32位虚拟机实际支持的内存为1.5~2G,64位无限制。
4."-Xss256k":设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
5."-XX:+AggressiveOpts":使用激进的优化特性,主要是在编译期间,jdk6就已经默认开启了,可以不指定,但需要测试效果,因为可能激进优化的假设不成立,优化后导致比如加载新类后类型继承结构变化、出现罕见陷阱等情况时(此处优化是由C2编译器进行),又会通过逆优化退回到解释转台继续执行(或者是C1编译器编译),反而降低了性能。
6."-XX:+UseBiasedLocking":使用偏向锁,也是jdk6的默认值,他的目的是消除数据在无竞争的情况下的同步原语,就是说把不需要同步的同步语句去掉。实现主要是偏向第一个使用该同步资源的线程,所以叫偏向锁。但这也是一个带有效益权衡性质的优化,如果代码中大多数同步语句都是数据有竞争的情况下,禁止("-XX:-UseBiasedLocking")反而可以提升性能。
7."-XX:PermSize=128M -XX:MaxPermSize=256M":分别设置永久代初始大小,和永久代最大大小。永久代也就是方法区,虽然是永久代但其实也并不是永远不变,因为会涉及到类型的卸载,不过卸载类的要求相当严格。
8."-XX:+DisableExplicitGC":忽略用户代码中手动调用GC(system.gc())。
9."-XX:MaxTenuringThreshold=31":新生代中对象的年龄到达多少岁时晋升到老年代(一次minorGC年龄加1),该默认值为15。需要注意的是JVM为了适应不同程序的内存状况并不是一定要求只有年龄达到MaxTenuringThreshold才能晋升到老年代,如果在Survicor空间中相同年龄所有对象大小的和大于Survivor空间的一半,年龄大于或等于该年龄的对象就会直接进入老年代,这称为动态对象年龄判定。例如,在上述配置条件下,新生代默认占对内存的1/3(其余为老年代,可以通过"-Xmn768m"来指定新生代大小为768m),则默认的Survivor区占新生代的1/10大致为68m,如果此时执行minorGC时,Eden区域存活的对象中10岁的对象的大小的和大于68M,那么这次minorGC之后,Eden区域中存活的大于或等于10岁的对象就都会直接进入老年代,而不是等到31岁。
注:因为新生代的对象大多具备朝生夕死的特点,新生代一般采取复制算法,这样效率会很快,具体为将新生代分为三块区域,Eden区和两块Survivor区比例为8:1(可以通过配置"-XX:SurvivorRatio=8"指定新生代中Eden:Survivor为8:1,默认比例),每次只使用Eden区和一块Survivor区(即使用新生代的90%,只会浪费10%的空间,而且据IBM公司的研究,新生代中98%的对象都是朝生夕死),剩下一块Survivor区用作minorGC时将原来Eden区和另一块Survivor区存活的对象复制过去,而此时如果这块Survivor区不够用就需要向老年代分配(比如上述的动态对象年龄判定条件满足时)。
10."XX:+UseConcMarkSweepGC":使用Concurrent Mark Sweep收集器(CMS收集器)。其主要特点是获取最短回收停顿时间的收集器,其收集步骤分为4步:初始标记(CMS initial mark),并发标记(CMS concurrent mark),重新标记(CMS remark),并发清除(CMS concurrent sweep)。其中初始标记和重新标记仍需要Stop The World,但初始标记只是标记GC Roots能直接关联到的对象(采用的垃圾收集算法为根搜索算法),并发标记就是进行GC Roots搜索确定对象是否“已死”,而重新标记是为了修正并发标记时程序继续运作造成的改变,重新标记需要的时间远低于并发标记,所以整个收集过程停顿时间会很短,如下图:
11."-XX:+UseParNewGC":新生代采用ParNew收集器。ParNew收集器除了多线程收集之外其他和Serial收集器类似,以致在单cpu情况下效果不如Serial,甚至双cpu情况下由于线程交互开销也不能完全保证比Serial更优秀。但是,采用它的原因是只有它能与CMS收集器配合工作。其收集过程如下图:
12."-XX:+CMSParallelRemarkEnabled":使CMS垃圾收集时,第二次标记(前文描述CMS中的重新标记)采用多线程方式,本人没有测试默认值是否开启。
13."-XX:+UseCMSCompactAtFullCollection":设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理,默认开启,关闭可能会导致老年代碎片过多分配大对象失败。
14."-XX:LargePageSizeInBytes=96m":设置java进程大内存页每页大小,需要操作系统支持。详细请参见博客:http://kenwublog.com/tune-large-page-for-jvm-optimization
15."-XX:-UseFastAccessorMethods":设置关闭快速调用成员方法,这里表述可能不是太准确。首先说明一下什么方法叫做AccessorMethods,①必须是成员方法,静态方法不行,②返回值类型必须是引用类型或者int,其它都不算,③方法体的代码必须满足aload_0; getfield #index; areturn或ireturn这样的模式,方法名是什么都没关系,是不是get、is、has开头都不重要。 因为此类方法方法体很简单,而且没有方法计数器,开启此设置后可以跳过对该类方法的编译,详细参见http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2011-March/005057.html该设置默认在jdk6中是开启的,但由于jdk7的server模式默认开启了多层编译,此时在这种多台方法调用时甚至会导致性能下降,所以设置关闭(jdk7是否默认关闭不太清楚),但仍需要根据自己项目测试。
16."-XX:CMSInitiatingOccupancyFraction=70":CMS垃圾收集老年代时触发条件,当老年代使用的比例占用到整个老年代的70%时,执行一次Full GC(major GC),默认值90%,如有错误还请留言指正。
注:本人没有自己编译过JDK,网上资料主要有两种说法,90%和68%,经本人在上述环境测试,没有设置改制时应用运行一段时间会自己挂掉,没有输出任何日志,gc日志显示正在执行minor GC时突然挂掉,配置为70%后没有出现过这种情况,所以我偏向认为默认值为90%。
17."-XX:+UseCMSInitiatingOccupancyOnly":CMS GC触发的条件为旧生代已使用的空间达到设定的CMSInitiatingOccupancyFraction百分比,例如默认CMSInitiatingOccupancyFraction为90%,如旧生代空间为1 000MB,那么当旧生代已使用的空间达到900MB时,CMS GC即开始执行;另外一种触发方式是JVM自动触发,JVM基于之前GC的频率及旧生代的增长趋势来评估决定什么时候执行CMS GC,如果不希望JVM自行触发,可设置该参数。
18."-verbose:gc":输出GC前后内存情况,但并不详细,如,
19."-Xloggc:../logs/gc.log":将GC日志输出到gc.log文件中,此处是相对路径,Tomcat则是在TOMCAT_HOME/logs/gc.log。
20."-XX:+PrintGCDetails":输出GC的详细信息,如,
100.667: [Full GC [Tenured: 0K->210K(10240K), 0.0149142 secs] 4603K->210K(19456K), [Perm : 2999K->2999K(21248K)], 0.0150007 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
其中33.125指的是JVM启动之后经过的时间,GC指的就是minor GC,DefNew指的是新生代(默认的收集器),3324K(GC前)->152K(GC后)(3712K(总大小)),0.0025925花费的时间3324K->152K(11904K)指的是整个JVM堆的大小变化,后面的Full GC中Tenured既是老年代,此处应该是新生代对象晋升到老年代所以导致老年代大小反而增加。Perm既是永久代,后面的user,sys,real和Linux的time命令输出时间含义一致,分别代表用户态消耗的CPU时间、内核态消耗的CPU时间以及操作从开始到结束所经过的真实时间。
21."-Djava.awt.headless=true": Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。 Headless模式虽然不是我们愿意见到的,但事实上我们却常常需要在该模式下工作,尤其是服务器端程序开发者。因为服务器(如提供Web服务的主机)往往可能缺少前述设备,但又需要使用他们提供的功能,生成相应的数据,以提供给客户端(如浏览器所在的配有相关的显示设备、键盘和鼠标的主机)。 一般是在程序开始激活headless模式,告诉程序,现在你要工作在Headless mode下,如果服务程序并不需要图像处理可以不设置。
22."-Djava.net.preferIPv4Stack=true":禁用IPv6,因为本人应用中会用到JGroups作为分布式内存数据库,而在使用IPv6的地址会无法识别加入到集群,所以禁用掉了,大家可以根据自己应用情况决定。
相关推荐
本篇文件内容主要介绍了JVM优化的第三部分,重点围绕Tomcat参数调优、JVM参数调优、JVM字节码优化以及代码优化等几个方面。下面是针对这些知识点的详细解释: 1. Tomcat参数调优 在Tomcat参数调优部分,首先介绍了...
### Tomcat JVM内存设置方法详解 #### 一、前言 Tomcat作为一款广泛使用的Java应用服务器,其性能优化一直是开发者关注的重点之一。而在性能优化的过程中,合理设置JVM(Java Virtual Machine)内存是非常关键的一...
【标题】"Tomcat JVM参数调优"涉及的是在运行Apache Tomcat服务器时优化Java虚拟机(JVM)性能的过程。Tomcat是一个流行的开源Java应用服务器,它用于部署和运行Java Servlets和JavaServer Pages(JSP)。由于JVM是...
【描述】:“Tomcat7性能优化调优Tomcat7性能优化调优Tomcat7性能优化调优”重复强调了对Tomcat7版本的性能调整,这可能涉及到内存管理、线程池设置、连接器配置、JVM参数优化等多个方面。性能调优的目标是提高...
Java虚拟机(JVM)是运行Java应用程序的关键组件,它负责管理程序...总之,理解JVM内存管理和设置是优化Tomcat性能的关键。通过对代码的优化和合理的JVM内存配置,可以有效地防止内存溢出,提高服务器的稳定性和效率。
为了帮助开发者解决这个问题,本文将介绍 Tomcat 优化方案的七个方面,分别是增加 JVM 堆内存大小、修复 JRE 内存泄漏、线程池设置、压缩、数据库性能调优、Tomcat 本地库和其它选项。 增加 JVM 堆内存大小 Tomcat...
- **内存配置**:如果Tomcat的JVM(Java虚拟机)内存设置过低,特别是在处理大量并发请求或运行内存密集型应用时,可能会导致内存溢出错误,从而触发Tomcat自动关闭。 - **连接超时**:如果Tomcat的连接器...
### Tomcat JVM 内存调整方法与原理 #### 一、背景介绍 在日常的运维工作中,经常会遇到 Tomcat 应用服务器出现内存溢出的问题,表现为 `java.lang.OutOfMemoryError` 异常。这类问题通常是由于 JVM(Java 虚拟机...
优化主要包括两大部分:外部环境调整和Tomcat自身的调整。首先,我们来探讨一下外部环境的优化,特别是JAVA虚拟机性能优化和操作系统性能优化。 1. **JAVA虚拟机性能优化** Tomcat依赖JVM运行,因此JVM的性能直接...
### JVM内存配置优化 #### 一、理解JVM内存模型 在进行JVM内存配置优化之前,我们需要...以上就是关于JVM内存配置优化以及Tomcat并发配置优化的相关知识点。通过合理的配置调整,可以有效提升系统的稳定性和性能。
总结,Tomcat的启动优化和并发优化是一个综合性的过程,涉及到JVM参数、服务器配置、应用代码等多个层面。开发者需根据实际场景进行调整,以达到最佳的运行效果。以上策略只是基础,实际优化过程中还需结合监控工具...
在Java应用服务器中,尤其是Tomcat这样的轻量级应用服务器,JVM(Java虚拟机)的性能优化至关重要。"jvm优化参数配置"是确保Tomcat稳定运行的关键环节,能够提高应用的响应速度,减少内存泄露,提升系统整体性能。...
本文档旨在深入探讨Tomcat的性能调优原理及实践方法,帮助技术人员更好地理解和实施相关的优化措施。 #### 二、Tomcat性能调优概览 Tomcat的性能调优主要包括两大类:外部环境调优与自身调优。外部环境调优关注于...
虽然在课程中还讲解了部分HTTP协议的技术,但是课程的重点还是NGINX、JVM、Tomcat三相运维与配置技术。课程内容包括了Nginx进阶基础,Nginx配置提升,JVM虚拟机尝试,JVM运维实用排障工具,JVM监控工具,Tomcat配置...
《Tomcat架构解析与优化》一书主要涵盖了Apache Tomcat服务器的基础架构、工作原理以及性能调优策略。Tomcat作为一款广泛使用的Java Servlet容器,它的高效运行和优化对于任何Java Web应用都至关重要。 首先,...
【描述】:本文旨在探讨如何通过优化Tomcat和Oracle的相关参数来提升系统性能,确保应用在高并发情况下依然保持高效运行。文章不仅表达了对一位曾分享过“Tomcat如何承受1000个用户”知识的敬意,同时也是对原文的...
自身调优主要包括对Tomcat内部组件及配置的优化,以达到最佳性能表现。 - **连接器配置优化**:调整Tomcat连接器的相关参数,如最大连接数、空闲时间等。 - **线程池配置**:合理设置线程池大小,以平衡响应时间和...
总结,Tomcat部署及优化是一个涉及多方面的工作,包括JDK的配置、Tomcat的启动与部署、JVM参数调整、服务器配置优化以及应用本身的性能提升。每个环节都需要细致考虑,以确保Tomcat能够高效、稳定地运行Web应用程序...
通过对 Tomcat 的 JKD OPTS、NIO 配置、线程池及 JVM 参数等关键部分进行细致调整,可以显著提升应用服务器的整体性能。合理的资源配置不仅能够提高应用响应速度,还能够降低资源消耗,提升系统的稳定性和安全性。在...
优化工作主要分为两大部分:外部环境调整和Tomcat自身的配置优化。 1. **外部环境优化** - **操作系统**:优化操作系统参数以适应Tomcat的需求,如增加内存容量、提升CPU性能、优化文件系统读写速度,以及针对高...