Tomcat优化整理(Linux)
####JVM内存 调优
#####内存划分
虚拟机中的共划分为三个代:新生代(Young Generation)、老年代(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系不大。新生代和年老代的划分是对垃圾收集影响比较大的。
空间 | 命令行选项 | 占用倍数 |
---|---|---|
Java堆 | -Xms和-Xmx | 3~4倍Full GC后的老年代空间占用量 |
持久代 | -XX:PermSize -XX-MaxPersize |
1.2~1.5倍Full GC后的永久带空间占用量 |
新生代 | -Xmn | 1~1.5倍Full GC后的老年代空间占用量 |
老年代 | Java堆大小减新生代大小 | 2~3倍Full GC后的老年代空间占用量 |
A.新生代
所有新生成的对象首先都是放在新生代的。新生代的目标就是尽可能快速的收集掉那些生命周期短的对象。新生代分三个区。一个Eden[取自圣经伊甸园]区,两个Survivor区(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。
B.老年代
在新生代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
C.持久代
用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=
GC分类
A.Scavenge GC
一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。
B.Full GC
对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个对进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:
- 年老代(Tenured)被写满
- 持久代(Perm)被写满
- System.gc()被显示调用
- 上一次GC之后Heap的各域分配策略动态变化
调优
A.java.lang.OutOfMemoryError: Java heap space
表示堆内存空间满了,如果不是程序逻辑的bug,可能是因为项目中引用的jar比较多,导到内存溢出。JVM默认堆的最小使用内存为物理内存的1/64,最大使用内存为物理内存的1/4,如8G的物理内存,JVM默认堆的最小和最大内存分别为128m和2048m。通过调整JVM的-Xms(初始内存)和-Xmx(最大内存)两个参数加大内存使用限制。
B.java.lang.OutOfMemoryError: PermGen space异常
表示静态内存区满了,通常是由于加载的类过多导致。jdk8以下版本通过修改JVM的-XX:PermSize和-XX:MaxPermSize两个参数,限制静态区最小和最大内存范围。jdk8改变了内存模型,将类定义存放到了元数据(MetaspaceSize)空间,而元数据空间是与堆空间共享同一块内存区域的,所以在JDK8以后版本不会存在PermGen space异常了,故不用设置此参数。
C.java.lang.StackOverflowError异常
表示栈内存溢出。通常是由于死循环、无限递归导致。
解决办法:修改catalina.bat文件
set JAVA_OPTS=-Xms*m
-Xmx*m
-XX:PermSize=*M
-XX:MaxNewSize=*m
-XX:MaxPermSize=*m
-xms:指定初始堆内存大小
-xmx:指定最大堆内存大小
说明:如果-Xmx不指定或者指定偏小,应用可能会导致java.lang.OutOfMemory错误,此错误来自JVM不是Throwable的,无法用try...catch捕捉。
PermSize和MaxPermSize指明虚拟机为java永久生成对象(Permanate generation)
-XX:PermSize=最小尺寸,初始分配 -XX:MaxPermSize=最大允许分配尺寸,按需分配 过小会导致:java.lang.OutOfMemoryError: PermGen space
1、慎用最小限制选项Xms,PermSize已节约系统资源。
并发配置优化
当一个进程有 500 个线程在跑的话,那性能已经是很低很低了。Tomcat 默认配置的最大请求数是 150,也就是说同时支持 150 个并发,当然了,也可以将其改大。
当某个应用拥有 250 个以上并发的时候,应考虑应用服务器的集群。
在tomcat配置文件server.xml中的
minProcessors:最小空闲连接线程数,用于提高系统处理性能,默认值为10
maxProcessors:最大连接线程数,即:并发处理的最大请求数,默认值为75
acceptCount:允许的最大连接数,应大于等于maxProcessors,默认值为100
enableLookups:是否反查域名,取值为:true或false。为了提高处理能力,应设置为false
connectionTimeout:网络连接超时,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。通常可设置为30000毫秒。
其中和最大连接数相关的参数为maxProcessors和acceptCount。如果要加大并发连接数,应同时加大这两个参数。
web server允许的最大连接数还受制于操作系统的内核参数设置,通常Windows是2000个左右,Linux是1000个左右。Unix中如何设置这些参数,请参阅Unix常用监控和管理命令
maxThreads 是处理请求的线程数,
acceptCount 是等待队列,acceptCount并不是一定要大于等于maxThreads。 maxThreads 满了,进入acceptCount ,acceptCount 也满了,则 拒绝请求