在目前流行的互联网架构中,Tomcat在目前的网络编程中是举足轻重的,由于Tomcat的运行依赖于JVM,从虚拟机的角度把Tomcat的调整分为外部环境调优JVM和Tomcat自身调优两部分。

  1. 外部环境调优JVM

1.1 JVM组成

    JVM由Class Loader Subsystem(类加载子系统)、Runtime Data Areas(运行时数据区)、Execution Engine(执行引擎)和Native Method Interface(本地方法接口)四部分组成,具体如下图所示。

总结Tomcat优化方法_Tomcat

    其中,类加载子系统使用Java语言编写.java Source Code文件,通过javac编译成.class Byte Code文件,class loader类加载器将所需所有类加载到内存,必要时将类实例化成实例;运行时数据区最消耗内存的空间,需要优化;执行引擎包括JIT(JustInTimeCompiler)即时编译器和GC垃圾回收器;本地方法接口将本地方法栈通过JNI(Java Native Interface)调用Native Method Libraries, 如C、C++库等,扩展Java功能,融合不同的编程语言为Java所用。

    JVM运行时数据区包括以下几个部分:

    ①Method Area (线程共享)方法区是所有线程共享的内存空间,存放已加载的类信息(构造方法,接口定义)、常量(final)和静态变量(static),运行时常量池等,但实例变量存放在堆内存中,从JDK8开始此空间由永久代改名为元空间;

    ②heap (线程共享)堆在虚拟机启动时创建,存放创建的所有对象信息,如果对象无法申请到可用内存将抛出OOM异常,堆是靠GC垃圾回收器管理的,通过-Xmx -Xms 指定最大堆和最小堆空间大小;

    ③Java stack (线程私有)Java栈是每个线程会分配一个栈,存放java中8大基本数据类型、对象引用、实例的本地变量、方法参数和返回值等,基于FILO()(First In Last Out),每个方法为一个栈帧;

   ④Program Counter Register (线程私有)PC寄存器就是一个指针,指向方法区中的方法字节码,每一个线程用于记录当前线程正在执行的字节码指令地址。由执行引擎读取下一条指令,因为线程需要切换,当一个线程被切换回来需要执行的时候,知道执行到哪里了;

    ⑤Native Method stack (线程私有)本地方法栈为本地方法执行构建的内存空间,存放本地方法执行时的局部变量、操作数等。

    *所谓本地方法,是指使用native关健字修饰的方法,比如Thread.sleep方法,简单的说是非Java实现的方法,例如操作系统的C编写的库提供的本地方法,Java调用这些本地方法接口执行。但是要注意,本地方法应该避免直接编程使用,因为Java可能跨平台使用,如果用了Windows API,换到了Linux平台部署就有了问题。

1.2 GC (Garbage Collection) 垃圾收集器

    在堆内存中如果创建的对象不再使用后仍占用着内存,此时即为垃圾,需要及时进行垃圾回收,从而释放内存空间给其它对象使用。堆内存里面经常创建、销毁对象,内存也是被使用、被释放,如果不妥善处理,一个使用频繁的进程,可能会出现虽然有足够的内存容量,但是无法分配出可用内存空间,因为没有连续成片的内存了,内存全是碎片化的空间。所以需要有合适的垃圾回收机制来确保正常释放不再使用的内存空间,还需要保证内存空间尽可能的保持一定的连续。

    对于垃圾回收,需要解决以下三个问题:

    ①哪些是需要回收的垃圾?

    ②怎么回收垃圾?

    ③什么时候回收垃圾?

1.2.1 Garbage垃圾确定方法

    Garbage垃圾确定方法常用的方法包括:

    ①引用计数: 每一个堆内对象上都与一个私有引用计数器,记录着被引用的次数,引用计数清零后该对象所占用堆内存就可以被回收。循环引用的对象都无法将引用计数归零,就无法清除,在Python中使用的就是此种方式。

    ②根搜索(可达)算法Root Searching:在内存中存在着很多的对象,这些对象如果能在线程栈变量、静态变量、常量池和Java本地监控中被引用,则是可以继续保留的对象,如果不能被这些变量所引用,则被认为是垃圾,要进行清理。

1.2.2 垃圾回收基本算法

1.2.2.1 标记-清除 Mark-Sweep

    该算法将垃圾分为标记阶段和内存释放阶段,标记阶段找到所有可访问对象打个标记,清理阶段遍历整个堆,对未标记对象(即不再使用的对象)逐一进行清理。

    标记-清除最大的问题是会造成内存碎片,但是不浪费空间,效率较高(如果对象较多,逐一删除效率也会影响)

1.2.2.2 标记-压缩 (压实)Mark-Compact

    该算法分为垃圾标记阶段和内存整理阶段,标记阶段找到所有可访问对象打个标记;内存清理阶段时整理时将对象向内存一端移动,整理后存活对象连续的集中在内存一端。

    标记-压缩算法好处是整理后内存空间连续分配,有大段的连续内存可分配,没有内存碎片。缺点是内存整理过程有消耗,效率相对低下。

1.2.2.3 复制 Copying

    复制算法先将可用内存分为大小相同两块区域A和B,每次只用其中一块,比如A,当A用完后,则将A中存活的对象复制到B,复制到B的时候连续的使用内存,最后将A一次性清除干净。

    该算法的好处是没有碎片,复制过程中保证对象使用连续空间,且一次性清除所有垃圾,所以效率很高;缺点是比较浪费内存,只能使用原来一半内存,因为内存对半划分了,复制过程毕竟也是有代价。

1.2.2.4 多种算法总结

    以上算法没有哪一种能说是最好的,需要根据实际场景来做选择:

    ①效率: 复制算法>标记清除算法> 标记压缩算法;

    ②内存整齐度: 复制算法=标记压缩算法> 标记清除算法;

    ③内存利用率: 标记压缩算法=标记清除算法>复制算法。

1.2.2.5 STW

    对于大多数垃圾回收算法而言,GC线程工作时,停止所有工作的线程,称为Stop The World,GC 完成时恢复其他工作线程运行,这也是JVM运行中最头疼的问题。

1.2.3 分代堆内存GC策略

    以上的垃圾回收算法都有各自的优缺点,能不能对不同数据进行区分管理,不同分区对数据实施何种回收策略,需要分而治之。

1.2.3.1 堆内存分代

    堆内存分代将heap内存空间分为年轻代(Young Generation)、老年代(Old Generation)和持久代(Permanent Generation)三部分,不过对于持久代到底属不属于堆也有不同版本的说法,我们可以理解为组织结构上是属于堆,但实际使用中则不属于堆。

总结Tomcat优化方法_java_02

    年轻代包括伊甸园区(Eden)和幸存区(Servivor Space)两部分,伊甸园区只有一个,里面为新创建的对象;幸存区有两个,分别为from区(本次复制数据的源区)和to区(本次复制数据的目标区),两者大小相等、地位相同,并且可互换身份。老年代里保存的是长时间存活的对象。

    持久代在JDK1.7之前使用即为Method Area方法区,用于保存JVM自身的类和方法,存储JAVA运行时的环境信息。JDK1.8后改名为 MetaSpace,此空间不存在垃圾回收,关闭JVM会释放此区域内存,此空间物理上不属于heap内存,但逻辑上存在于heap内存。

总结Tomcat优化方法_Tomcat_03

1.2.3.2 年轻代回收Minor GC

    年轻代回收的工作流程为:

    ①起始时所有新建对象(特大对象直接进入老年代)都出生在eden,当eden满了,启动GC,这个称为Young GC或者Minor GC;

    ②先标记eden存活对象,然后将存活对象复制到s0(假设本次是s0,也可以是s1,它们可以调换),eden剩余所有空间都清空,GC完成;

    ③继续新建对象,当eden再次满了,启动GC;

    ④先同时标记eden和s0中存活对象,然后将存活对象复制到s1,将eden和s0清空,此次GC完成;

    ⑤继续新建对象,当eden满了,启动GC;

    ⑥先标记eden和s1中存活对象,然后将存活对象复制到s0,将eden和s1清空,此次GC完成。

    以后就重复上面的步骤。。。。。。

    通常场景下大多数对象都不会存活很久,而且创建活动非常多,新生代就需要频繁垃圾回收。但如果一个对象一直存活,它就会在from、to来回复制,当from区中对象复制次数达到阈值(默认15次,CMS为6次,可通过java的选项 -XX:MaxTenuringThreshold=N 指定),就直接复制到老年代。

1.2.3.3 老年代回收Major GC

    进入老年代的数据较少,所以老年代区被占满的速度较慢,垃圾回收相对也不频繁。如果老年代也满了,会触发老年代GC,称为Old GC或者Major GC。由于老年代对象一般来说存活次数较长,所以较常采用标记-压缩算法。当老年代满时会触发Full GC,即对所有"代"的内存进行垃圾回收。

    Minor GC比较频繁,Major GC较少,但一般Major GC时,由于老年代对象也可以引用新生代对象,所以先进行一次Minor GC,然后在Major GC会提高效率,可以认为回收老年代的时候完成了一次Full GC,因此也可以MajorGC = FullGC。

1.2.3.4 GC触发条件

    根据以上的不同策略,GC触发条件也不同:

    ①Minor GC触发条件:当eden区满了触发;

    ②Full GC触发条件:老年代满了,或者System.gc()手动调用(不推荐)

    ③年轻代:存活时长低,或者适合复制算法的;

    ④老年代:区域大、存活时长高,或者适合标记压缩算法的;

1.2.4 Java内存调整相关参数

1.2.4.1 JVM内存常用相关参数

    JVM内存常用的参数选项可分为三类:

    ①-选项名称:此为标准选项,所有HotSpot都支持;

    ②-X选项名称:此为稳定的非标准选项;

    ③-XX:选项名称:非标准的不稳定选项,下一个版本可能会取消。

    关于JVM内存常用参数及说明请见下表:

参数

说明

范例


-Xms

设置应用程序初始使用的堆内存大小(年轻代+老年代)


-Xms2g


-Xmx

设置应用程序能获得的最大堆内存,早期JVM不建议超过32G,内存管理效率下降


-Xms4g

-XX:NewSize

设置初始新生代大小

-XX:NewSize=128m

-XX:MaxNewSize

设置最大新生代内存空间

-XX:MaxNewSize=256m 


-Xmnsize

同时设置-XX:NewSize 和 -XX:MaxNewSize,代替两者


-Xmn1g

-XX:NewRatio

以比例方式设置新生代和老年代

-XX:NewRatio=2

new/old=1/2


-XX:SurvivorRatio 

以比例方式设置eden和survivor(S0或S1) 

-XX:SurvivorRatio=6

eden/survivor=6/1

new/survivor=8/1


-Xss

设置每个线程私有的栈空间大小,依据具体线程大小和数量


-Xss256k

1.2.4.2 Tomcat的JVM参数设置

    默认情况下,Tomcat的JVM参数是未指定的,-Xmx大约使用了1/4的内存。我们可手动在Tomcat中bin子目录下的catalina.sh文件中添加如下图所示的一行相关参数,-server选项指定VM运行在server模式,为在服务器端最大化程序运行速度而优化 ,同时可设置初始内存和最大内存、初始和最大新生代内存大小等。重启Tomcat服务后,查看进程信息,可以直接看到Tomcat中的JVM相关参数,如果在浏览器中对比查看的话,相关JVM设置的变化效果会更明显。

总结Tomcat优化方法_Tomcat_04

总结Tomcat优化方法_垃圾回收器_05

总结Tomcat优化方法_Tomcat_06

总结Tomcat优化方法_Tomcat_07

1.2.5 垃圾收集方式

    垃圾收集方式可根据工作模式和回收线程数分为两大类,按工作模式不同指的是GC线程和工作线程是否一起运行,它包括:

    ①独占垃圾回收器:只有GC在工作,STW一直进行到回收完毕,工作线程才能继续执行;

    ②并发垃圾回收器:让GC线程垃圾回收某些阶段可以和工作线程一起进行,如标记阶段并行,回收阶段仍然串行。

    按回收线程数指的是GC线程是否串行或并行执行,它包括:

    ①串行垃圾回收器:一个GC线程完成回收工作;

    ②并行垃圾回收器:多个GC线程同时一起完成回收工作,充分利用CPU资源。

1.2.6 调整策略

    具体使用哪种垃圾回收策略,与Java运行的具体环境密切相关,JVM的调优在以下场景都可以用到:

    ①在WEB领域中,如Tomcat等;

    ②在大数据领域,如Hadoop生态各组件;

    ③在消息中间件领域的Kafka等;

    ④在搜索引擎领域的ElasticSearch、Solr等。

    在JVM调优时,需要注意减少STW时长,把串行变为并行;同时要减少GC 次数,分配合适的内存大小。一般情况下可用到以下几个原则:

    ①客户端或较小程序,内存使用量不大,可以使用串行回收;

    ②对于服务端大型计算,可以使用并行回收;

    ③大型WEB应用,用户端不愿意等待,尽量少的STW,可以使用并发回收。

1.2.7 垃圾回收器

1.2.7.1 常用垃圾回收器

    常用的垃圾回收器可分为两类,一类是专属的代所使用的,如Serial、Parallel Scavenge专属新生代使用,CMS、Serial Old专属老年代使用;另一类是不明确分代、单独设置使用的,如G1、ZGC等。

总结Tomcat优化方法_老年代_08

1.2.7.1.1 按分代设置不同垃圾回收器

    新生代的垃圾收回器及功能说明等如下:

    ①Serial收集器:单线程、独占式串行,采用复制算法,简单高效,但会造成STW。

    ②PS(Parallel Scavenge)收集器:多线程并行、独占式,会产生STW,使用复制算法关注调整吞吐量,此收集器关注点是达到一个可控制的吞吐量。吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),比如虚拟机总共运行100分钟,其中垃圾回收花掉1分钟,那吞吐量就是99%。 高吞吐量可以高效率利用CPU时间,尽快完成运算任务,主要适合在后台运算而不需要太多交互的任务。 除此之外,Parallel Scavenge收集器具有自适应调节策略,它可以将内存管理的调优任务交给虚 拟机去完成。自适应调节策略也是Parallel Scavenge与 ParNew 收集器的一个重要区别。 和ParNew不同,PS不可以和老年代的CMS组合。

    ③ParNew收集器:就是Serial收集器的多线程版,将单线程的串行收集器变成了多线程并行、独占式,使用复制算法,相当于PS的改进版。经常和CMS配合使用,关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,适合需要与用户交互的程序,良好的响应速度能提升用户体验。

    老年代的垃圾回收器及功能说明如下:

    ①Serial Old收集器:Serial Old是Serial收集器的老年代版本,单线程、独占式串行,回收算法使用标记压缩。

    ②Parallel Old收集器:多线程、独占式并行,回收算法使用标记压缩,关注调整吞吐量。Parallel Old收集器是Parallel Scavenge收集器的老年代版本,这个收集器是JDK1.6之后才开始提供,从HotSpot虚拟机的垃圾收集器的图中也可以看出,Parallel Scavenge 收集器无法与CMS收集器配合工作,因为一个是为了吞吐量,一个是为了客户体验(也就是暂停时间的缩短)

    ③CMS (Concurrent Mark Sweep并发标记清除算法)收集器 :在某些阶段尽量使用和工作线程一起运行,减少STW时长(200ms以内),提升响应速度,是互联网服务端BS系统上较佳的回收算法;分为初始标记、并发标记、重新标记、并发清除4个阶段,在初始标记、重新标记时需要STW。初始标记阶段需要STW,只标记一下GC Roots能直接关联到的对象,速度很快;并发标记阶段就是GC Roots进行扫描可达链的过程,为了找出哪些对象需要收集,这个过程远远慢于初始标记,但它是和用户线程一起运行的,不会出现STW,所有用户并不会感受到;重新标记阶段是为了修正在并发标记期间用户线程产生的垃圾,这个过程会比初始标记时间稍微长一点,但是也很快,和初始标记一样会产生STW;并发清理阶段发生在重新标记之后,对现有的垃圾进行清理,和并发标记一样也是和用户线程一起运行的,耗时较长(和初始标记比的话),不会出现STW。 由于整个过程中,耗时最长的并发标记和并发清理都是与用户线程一起执行的,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。

1.2.7.1.2 不分代、单独设置的垃圾回收器

    不明确分代、单独设置的垃圾回收器及功能说明如下:

    ①G1(Garbage First)收集器:是最新垃圾回收器,从JDK1.6实验性提供,JDK1.7发布,其设计目标是在多处理器、大内存服务器端提供优于CMS收集器的吞吐量和停顿控制的回收器。JDK9将G1设为默认的收集器,建议JDK9版本以后使用。基于标记压缩算法,不会产生大量的空间碎片,有利于程序的长期执行。 分为初始标记、并发标记、最终标记、筛选回收4个阶段,并发标记并发执行,其它阶段STW只有GC线程并行执行。 G1收集器是面向服务端的收集器,它的思想就是首先回收尽可能多的垃圾(这也是GarbageFirst名字的由来)。G1能充分的利用多CPU,多核环境下的硬件优势,使用多个CPU来缩短STW停顿的时间(10ms以内)。 可预测的停顿是G1相对于CMS的另一大优势,G1和CMS一样都是关注于降低停顿时间,但是G1能够让使用者明确的指定在一个M毫秒的时间片段内,消耗在垃圾收集的时间不得超过N毫秒。

    ②ZGC收集器:减少SWT时长(1ms以内), 可以PK C++的效率,目前实验阶段。

    ③Shenandoah收集器:和ZGC竞争关系,目前实验阶段。

    ④Epsilon收集器:调试 JDK 使用,内部使用,不用于生产环境。

    *JVM 1.8默认的垃圾回收器:PS+ParallelOld,所以大多数都是针对此进行调优 。

1.2.7.2 垃圾收集器设置

    优化调整Java相关参数的目标是尽量减少FullGC和STW,通过以下选项可以单独指定新生代、老年代的垃圾收集器:

    ①-server:指定为Server模式,也是默认值,一般使用此工作模式。

    ②-XX:+UseSerialGC:运行在Client模式下,新生代是Serial,老年代使用Serial Old。

    ③-XX:+UseParNewGC:新生代使用ParNew,老年代使用SerialOld。

    ④-XX:+UseParallelGC:运行于server模式下,新生代使用Serial Scavenge, 老年代使用SerialOld。

    ⑤-XX:+UseParallelOldGC:新生代使用Paralell Scavenge,老年代使用Paralell Old。-XX:ParallelGCThreads=N,在关注吞吐量的场景使用此选项增加并行线程数。

    ⑥-XX:+UseConcMarkSweepGC:新生代使用ParNew,老年代优先使用CMS,备选方式为Serial Old。响应时间要短,停顿短使用这个垃圾收集器。-XX:CMSInitiatingOccupancyFraction=N,N为0-100整数表示达到老年代的大小的百分比多少触发回收,默认值为68。开启“-XX:+UseCMSCompactAtFullCollection”,在CMS收集后,进行内存碎片整理。-XX:CMSFullGCsBeforeCompaction=N,设定多少次CMS后,进行一次内存碎片整理。-XX:+CMSParallelRemarkEnabled,降低标记停顿。

1.2.8 JAVA参数总结

    JAVA参数的相关名称、含义、默认值和说明等请参见下表:

参数名称

含义

默认值

说明



-Xms



初始堆大小



物理内存的1/64(<1GB)

默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制。



-Xmx



最大堆大小



物理内存的1/4(<1GB)

默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制







-Xmn






年轻代大小(1.4or lator) 


此处的大小是(eden+ 2 survivor space),与jmap -heap中显示的Newgen是不同的。整个堆大小=年轻代大小+年老代大小+持久代大小。增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8

-XX:NewSize

设置年轻代大小(for 1.3/1.4)



-XX:MaxNewSize

年轻代最大值(for 1.3/1.4) 



-XX:PermSize

设置持久代(perm gen)初始值 

物理内存的1/64 


-XX:MaxPermSize

设置持久代最大值

物理内存的1/4 











-Xss










每个线程的堆栈大小


JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈

大小为256K,更具应用的线程所需内存大小进行调整。在相同物理内存下减小这个值能生成更多的线程,但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。一般小的应用, 如果栈不是很深, 应该是128k够用的大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。

-XX:ThreadStackSize

线程堆栈大小






-XX:NewRatio


年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代) 


-XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年

轻代占整个堆栈的1/5。Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。 


-XX:SurvivorRatio


Eden区与Survivor区的大小比值 


设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10 


-XX:LargePageSizeInBytes

内存页的大小不可设置过大,会影响Perm的大小 



=128m

-XX:+UseFastAccessorMethods

原始类型的快速优化 



-XX:+DisableExplicitGC 

关闭System.gc() 


这个参数需要严格的测试








-XX:MaxTenuringThreshold








垃圾最大年龄


如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率该参数只有在串行GC时才有效

-XX:+AggressiveOpts

加快编译



-XX:+UseBiasedLocking

锁机制的性能改善



-Xnoclassgc

禁用垃圾回收





-XX:SoftRefLRUPolicyMSPerMB



每兆堆空闲空间SoftReference的存活时间


可达的对象在上次被引用后将保留一段时间。 缺省值是堆中每个空闲兆字节的生命周期的一秒钟



-XX:PretenureSizeThreshold



对象超过多大时直接在旧生代分配

0

单位字节新生代采用Parallel Scavenge GC时无效。另一种直接在旧生代分配的情况是大的数组对象,且数组中无外部引用对象

-XX:TLABWasteTargetPercent

TLAB占eden区的百分比

1%


-XX:+CollectGen0First

FullGC时是否先YGC

false



    并行收集器相关参数及说明如下表

参数名称

含义

默认值

说明



-XX:+UseParallelGC



Full GC采用parallelMSC


选择垃圾收集器为并行收集器。此配置仅对年轻代有效,即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集


-XX:+UseParNewGC


设置年轻代为并行收集


可与CMS收集同时使用。JDK5.0以

上JVM会根据系统配置自行设置,所以无需再设置此值

-XX:ParallelGCThreads

并行收集器的线程数 


此值最好配置与处理器数目相等,同样适用于CMS


-XX:+UseParallelOldGC

年老代垃圾收集方式为并行收集(ParallelCompacting) 



JAVA 6出现的参数选项


-XX:MaxGCPauseMillis

每次年轻代垃圾回收的最长时间(最大暂停时间) 


如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值




-XX:+UseAdaptiveSizePolicy




自动选择年轻代区大小和相应的

Survivor区比例


设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时一直打开

-XX:GCTimeRatio

设置垃圾回收时间占程序运行时间的百分比 



公式为1/(1+n)

-XX:+ScavengeBeforeFullGC

Full GC前调用YGC

true



  1. Tomcat性能优化常用配置

2.1 内存空间优化

    一台Tomcat服务器并发连接数不高,生产中建议分配的物理内存通常为4G到8G,如果需要更多连接,一般会利用虚拟化技术实现多台Tomcat。另外为了避免出现过多的碎片,建议将堆内存初始值和最大值设为相同值。

2.2 线程池调整

    Tomcat线程池的调整需要在conf目录下的server.xml文件中进行修改,常用的属性包括:

    ①connectionTimeout :连接超时时长,单位ms。

    ②maxThreads:最大线程数,默认200。

    ③minSpareThreads:最小空闲线程数。

    ④maxSpareThreads:最大空闲线程数。

    ⑤acceptCount:当启动线程满了之后,等待队列的最大长度,默认100。

    ⑥URIEncoding:URI地址编码格式,建议使用UTF-8。

    ⑦enableLookups:是否启用客户端主机名的DNS反向解析,缺省禁用,建议禁用,只使用客户端IP即可。

    ⑧compression:是否启用传输压缩机制,建议 "on",CPU和流量的平衡。compressionMinSize部分可启用压缩传输的数据流最小值,单位是字节;compressableMimeType部分可定义启用压缩功能的MIME类型,如text/html、text/xml、text/css和text/javascript等。