Tomcat 说明
-
使用tomcat的版本为tomcat-8.5.64
-
Java 版本为 jdk1.8.0_181
-
操作系统版本CentOS 7.6.1810
Tomcat配置
修改版本号
cat apache-tomcat-8.5.64/lib/catalina.jar/org/apache/catalina/util/ServerInfo.properties
# 下面修改成其他版本信息
server.info=Apache Tomcat/God-9.9
server.number=8.5.64.0
server.built=Mar 4 2021 23:14:16 UTC
修改shutdown 端口或者命令(安全)
# 修改shutdown端口或者命令,在本地避免误操作,造成应用关闭
# 修改server.xml 文件
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
# 可通过Telnet 127.0.0.1 8005 发送 SHUTDOWN 命令关闭tomcat应用
# telnet 127.0.0.1 8005
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
SHUTDOWN
Connection closed by foreign host.
HttpSession安全性考虑
# 防止客户端脚本读取Session Cookie内容进行诸如CSRF/XSS恶意http攻击,可在tomcat的conf/context.xml配置文件中配置
<Context useHttpOnly="true">
# 为自定义Cookie及属性添加HttpOnly属性,在Set-Cookie头部信息设置时可以添加“HttpOnly”
# 验证
抓包验证任意http响应的内容,确实任意客户端请求的回应包含“Set-Cookie:
Set-Cookie: JSESSIONID=7153B14B9E0DC8059A5840F9115129A6; Path=/demo; HttpOnly
# curl -Lv http://127.0.0.1:8080/demo/
* About to connect() to 127.0.0.1 port 8080 (#0)
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /demo/ HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:8080
> Accept: */*
>
< HTTP/1.1 200
< Set-Cookie: JSESSIONID=7153B14B9E0DC8059A5840F9115129A6; Path=/demo; HttpOnly
< Content-Type: text/html;charset=ISO-8859-1
< Content-Length: 12
< Date: Sun, 25 Apr 2021 06:08:57 GMT
<
hello world
* Connection #0 to host 127.0.0.1 left intact
设置会话超时时间(修改文件:web.xml)
# 默认会话超时时间为30 分钟,可根据实际情况酌情修改
vim apache-tomcat-8.5.64/conf/web.xml
<session-config>
<session-timeout>30</session-timeout>
</session-config>
Tomcat模式
各种模式的说明
-
BIO
-
bio(blocking I/O),顾名思义,即阻塞式I/O操作,表示Tomcat使用的是传统的Java I/O操作(即java.io包及其子包)。Tomcat在默认情况下,就是以bio模式运行的。遗憾的是,就一般而言,bio模式是三种运行模式中性能最低的一种。可以通过Tomcat Manager来查看服务器的当前状态或者启动的时候通过日志也可以查看运行模式
-
25-Apr-2021 13:32:41.931 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] 类似这样的启动日志
-
-
NIO
-
是Java SE 1.4及后续版本提供的一种新的I/O操作方式(即java.nio包及其子包)。Java nio是一个基于缓冲区、并能提供非阻塞I/O操作的Java API,因此nio也被看成是non-blocking I/O的缩写。它拥有比传统I/O操作(bio)更好的并发运行性能
-
-
APR
- (Apache Portable Runtime/Apache可移植运行库),是Apache HTTP服务器的支持库。你可以简单地理解为,Tomcat将以JNI的形式调用Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高Tomcat对静态文件的处理性能。 Tomcat apr也是在Tomcat上运行高并发应用的首选模式。
各种模式下的使用场景
-
BIO
-
同步并阻塞
-
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解
-
-
NIO
-
同步非阻塞
-
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
-
-
AIO(NIO2)
- 异步非阻塞
- AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
修改配置文件
修改配置文件模式(除了默认的配置,修改模式后都需要重启应用)
-
NIO
# tomcat8 默认为nio模式不需要配置server.xml
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-
NIO2
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000"
redirectPort="8443" />
-
APR
# 使用apr 模式需要安装一些软件包
# 方式一:
yum install apr apr-utils tomcat-native -y
# 方式二:
apr 安装
tar zxf apr-1.5.2.tar.gz -C /usr/local/src/
cd /usr/local/src/apr-1.5.2/
./configure --prefix=/usr/local/apr && make && make install
apr-utils 安装
tar zxf apr-util-1.5.4.tar.gz -C /usr/local/src/
cd /usr/local/src/apr-util-1.5.4/
./configure --with-apr=/usr/local/apr/ --prefix=/usr/local/apr-utils && make && make install
tomcat-native安装
cd /usr/local/apache-tomcat-7.0.65/bin/
tar zxf tomcat-native.tar.gz
cd tomcat-native-1.1.33-src/jni/native
./configure --with-apr=/usr/local/apr --with-java-home=/usr/local/java/ && make && make install
# 添加变量/etc/profile,使环境变量生效 source /etc/profie
JAVA_HOME=/usr/local/java
JAVA_BIN=$JAVA_HOME/bin
PATH=$PATH:$JAVA_BIN
CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JAVA_HOME JAVA_BIN PATH CLASSPATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/apr/lib
# server.xml
<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
connectionTimeout="20000"
redirectPort="8443" />
开启Tomcat 管理界面
-
默认tomcat 管理界面是没有打开的,需要配置apache-tomcat-8.5.64/conf/tomcat-users.xml
<role rolename="manager-gui"/> <role rolename="manager-script"/> <role rolename="manager-jmx"/> <user username="wuye" password="bamboo" roles="manager-gui,manager-script,manager-jmx"/> </tomcat-users>-
manager-gui : 允许访问html接口(即URL路径为/manager/html/*)
-
manager-script : 允许访问纯文本接口(即URL路径为/manager/text/*)
-
manager-jmx : 允许访问JMX代理接口(即URL路径为/manager/jmxproxy/*)
-
manager-status : 允许访问Tomcat只读状态页面(即URL路径为/manager/status/*)
-
从Tomcat Manager内部配置文件中可以得知,
manager-gui、manager-script、manager-jmx均具备manager-status的权限,也就是说,manager-gui、manager-script、manager-jmx三种角色权限无需再额外添加manager-status权限,即可直接访问路径/manager/status/*。
-
-
默认tomcat8的管理界面是只能在本地访问,如果需要在远程访问,需要配置apache-tomcat-8.5.64/webapps/manager/META-INF/context.xml
<Context antiResourceLocking="false" privileged="true" > <CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor" sameSiteCookies="strict" /> <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /> <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/> </Context>下面的修改过的参数,添加了允许“10.\d+.\d+.\d+” 访问web管理
<Context antiResourceLocking="false" privileged="true" > <CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor" sameSiteCookies="strict" /> <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|10\.\d+\.\d+\.\d+" /> <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/> </Context>
Tomcat 连接参数
# 查看执行器配置参数地址
https://tomcat.apache.org/tomcat-8.5-doc/config/executor.html
# 查看连接器配置参数地址
https://tomcat.apache.org/tomcat-8.5-doc/config/http.html
# 配置文件
# server.xml
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4" maxIdleTime="30000"/>
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
参数说明
执行器参数
| 参数 | 说明 |
|---|---|
| threadPriority | (int)执行程序中线程的线程优先级,默认值为 5(Thread.NORM_PRIORITY常量的值) |
| daemon | (布尔值)线程是否应该是守护程序线程,默认值为 true |
| namePrefix | (字符串)执行程序创建的每个线程的名称前缀。单个线程的线程名称将为namePrefix+threadNumber |
| maxThreads | (int)此池中活动线程的最大数量,默认为 200 |
| minSpareThreads | (int)始终保持活动状态的最小线程数(空闲和活动),默认值为 25 |
| maxIdleTime | (int)空闲线程关闭之前的毫秒数,除非活动线程的数目小于或等于minSpareThreads。默认值为60000(1分钟) |
| maxQueueSize | (int)在我们拒绝执行之前可以排队等待执行的可运行任务的最大数量。默认值为Integer.MAX_VALUE |
| prestartminSpareThreads | (布尔值)在启动执行程序时是否应启动minSpareThreads,默认值为 false |
| threadRenewalDelay | (长)如果配置了ThreadLocalLeakPreventionListener,它将通知此执行程序已停止的上下文。上下文停止后,池中的线程将更新。为避免同时更新所有线程,此选项设置了任意两个线程之间的延迟。该值以毫秒为单位,默认值为1000ms。如果value为负,则不更新线程。 |
maxSpareThreads : 最大备用线程数,一旦创建的线程超过这个值,Tomcat 就会关闭不再需要的 socket 线程,在tomcat-8.5 版本中已经取消了
连接器参数
列举常用参数,更多参数详见 tomcat.apache.org/tomcat-8.5-…
| 参数 | 说明 |
|---|---|
| asyncTimeout | 异步请求的默认超时(以毫秒为单位)。如果未指定,则此属性设置为Servlet规范默认值30000(30秒) |
| enableLookups | 设置为true是否要调用以 request.getRemoteHost()执行DNS查找以返回远程客户端的实际主机名。设置为false跳过DNS查找并改为以字符串形式返回IP地址(从而提高性能)。默认情况下,DNS查找被禁用。 |
| maxHeaderCount | 容器所允许的请求中的最大标头数。标头超过指定限制的请求将被拒绝。小于0的值表示没有限制。如果未指定,则使用默认值100。 |
| maxParameterCount | 容器将自动解析的参数和值对的最大数量(GET加POST)。超出此限制的参数和值对将被忽略。小于0的值表示没有限制。如果未指定,则使用默认值10000。请注意, FailedRequestFilter 过滤器可用于拒绝达到限制的请求。 |
| maxPostSize | 容器FORM URL参数解析将处理的POST的最大大小(以字节为单位)。可以通过将此属性设置为小于零的值来禁用该限制。如果未指定,则此属性设置为2097152(2兆字节)。请注意, FailedRequestFilter 可以使用拒绝超过此限制的请求。 |
| port | 将在其上创建服务器套接字并等待传入连接的TCP端口号。您的操作系统将仅允许一个服务器应用程序侦听特定IP地址上的特定端口号。如果使用特殊值0(零),则Tomcat将随机选择一个空闲端口用于此连接器。这通常仅在嵌入式和测试应用程序中有用 |
| protocol | 设置协议以处理传入流量。默认值为 HTTP/1.1使用自动切换机制选择基于Java NIO的连接器或基于APR / native的连接器。如果PATH(Windows)或LD_LIBRARY_PATH(在大多数Unix系统上)环境变量包含Tomcat本机库,并且AprLifecycleListener用于初始化APR的库的useAprConnector属性设置为 true,则将使用APR /本机连接器。如果找不到本机库或未配置属性,则将使用基于Java NIO的连接器。请注意,APR /本机连接器的HTTPS设置与Java连接器的设置不同。要使用显式协议而不是依赖于上述自动切换机制,可以使用以下值: org.apache.coyote.http11.Http11NioProtocol-非阻塞Java NIO连接器org.apache.coyote.http11.Http11Nio2Protocol-非阻塞Java NIO2连接器-APRorg.apache.coyote.http11.Http11AprProtocol/本地连接器。 |
| redirectPort | 如果此连接器支持非SSL请求,并且收到一个<security-constraint>要求进行SSL传输匹配 的请求,则Catalina将自动将请求重定向到此处指定的端口号。 |
| URIEncoding | 默认UTF-8 |
| acceptCount | 使用所有可能的请求处理线程时,传入连接请求的最大队列长度。队列已满时收到的任何请求都将被拒绝。默认值为100。 |
| acceptorThreadCount | 用于接受连接的线程数。在多CPU机器上增加此值,尽管您实际上并不需要超过此值2。另外,在有许多非保持活动连接的情况下,您可能还希望增加此值。默认值为 1。 |
| acceptorThreadPriority | 受体线程的优先级。用于接受新连接的线程。默认值为5(java.lang.Thread.NORM_PRIORITY常数的值 ) |
| compressibleMimeType | 该值为逗号分隔的MIME类型列表,可以对其使用HTTP压缩。默认值为 text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json,application/xml |
| compression | 所述连接器可在试图节省服务器的带宽使用HTTP / 1.1 GZIP压缩。该参数可接受的值为“ off”(禁用压缩),“ on”(允许压缩,这将导致压缩文本数据),“ force”(在所有情况下均强制进行压缩)或数字整数值(即等效于“ on”,但指定在压缩输出之前的最小数据量)。如果内容长度未知,并且压缩设置为“ on”或更具攻击性,则输出也将被压缩。如果未指定,则此属性设置为“ off”。 注意:在使用压缩(节省带宽)和使用sendfile功能(节省CPU周期)之间需要权衡。如果连接器支持sendfile功能(例如NIO连接器),则使用sendfile将优先于压缩。症状是大于48 Kb的静态文件将以未压缩的形式发送。您可以通过设置 useSendfile连接器的属性来关闭sendfile,如下所述,或者在DefaultServlet的配置(默认值 conf/web.xml或web.xmlWeb应用程序的)中更改sendfile的使用阈值 。 |
| connectionTimeout | 接受连接后,此连接器将等待要显示的请求URI行的毫秒数。使用值-1表示没有(即无限)超时。默认值为60000(即60秒),但请注意,Tomcat附带的标准server.xml将其设置为20000(即20秒)。除非disableUploadTimeout设置为false,否则在读取请求正文(如果有)时也会使用此超时 |
| connectionUploadTimeout | 指定在进行数据上载时要使用的超时(以毫秒为单位)。仅当disableUploadTimeout设置**为false时,**此选项才生效 。 |
| executor | 对Executor 元素中名称的引用。如果设置了此属性,并且命名的执行程序存在,则连接器将使用该执行程序,所有其他线程属性将被忽略。请注意,如果未为连接器指定共享执行器,则连接器将使用私有的内部执行器来提供线程池。 |
| keepAliveTimeout | 该连接器在关闭连接之前将等待另一个HTTP请求的毫秒数。默认值是使用为connectionTimeout属性设置的值 。使用值-1表示没有(即无限)超时 |
| maxConnections | 服务器在任何给定时间将接受和处理的最大连接数。达到此数目后,服务器将接受但不处理另一个连接。在处理的连接数降至maxConnections以下之前,该附加连接将被阻止,此时服务器将再次开始接受和处理新的连接。请注意,一旦达到限制,操作系统仍然可以根据该acceptCount设置接受连接。默认值因连接器类型而异。对于NIO和NIO2,默认值为10000。对于APR /本机,默认值为8192 |
| 参数 | 说明 |
|---|---|
| maxCookieCount | 请求允许的Cookie的最大数量。小于零的值表示没有限制。如果未指定,将使用默认值200。 |
| maxHttpHeaderSize | 请求和响应HTTP标头的最大大小,以字节为单位。如果未指定,则此属性设置为8192(8 KB) |
| maxKeepAliveRequests | 在服务器关闭连接之前可以管道传输的HTTP请求的最大数量。将此属性设置为1将禁用HTTP / 1.0保持活动以及HTTP / 1.1保持活动和流水线。将此设置为-1将允许无限数量的流水线或保持活动的HTTP请求。如果未指定,则此属性设置为100。 |
| maxThreads | 此Connector将创建的请求处理线程的最大数量,因此,它确定了可以处理的同时请求的最大数量。如果未指定,则此属性设置为200。如果执行程序与此连接器相关联,则此属性将被忽略,因为连接器将使用执行程序而不是内部线程池执行任务。请注意,如果配置了执行程序,则将正确记录为此属性设置的任何值,但是会报告该值(例如,通过JMX), -1以明确未使用该值。 |
| minSpareThreads | 始终保持运行状态的最小线程数。这包括活动线程和空闲线程。如果未指定,10 则使用默认值。如果执行程序与此连接器相关联,则此属性将被忽略,因为连接器将使用执行程序而不是内部线程池来执行任务。请注意,如果配置了执行程序,则将正确记录为此属性设置的任何值,但是会报告该值(例如,通过JMX),-1以明确未使用该值。 |
| SSLEnabled | 使用此属性可以在连接器上启用SSL通信。要在连接器上打开SSL握手/加密/解密,请将此值设置为true。默认值为false。true启用此值时,您还需要设置 scheme和secure属性,以将正确的request.getScheme()和 request.isSecure()值传递给servlet。 |
| scheme | 将此属性设置为希望通过调用返回的协议的名称request.getScheme()。例如,https对于SSL连接器,您可以将此属性设置为“ ”。默认值为“ http”。 |
| secure | 将此属性设置为,true如果您希望调用request.isSecure()以返回true 此连接器收到的请求。您可能希望在从SSL加速器(例如加密卡,SSL设备甚至Web服务器)接收数据的SSL连接器或非SSL连接器上使用它。默认值为false。 |
| tcpNoDelay | 如果设置为true,则将在服务器套接字上设置TCP_NO_DELAY选项,这可以在大多数情况下提高性能。默认情况下设置为true |
连接器的差别
| NIO | NIO2 | APR/本地连接器 | |
|---|---|---|---|
| ClassName | Http11NioProtocol | Http11Nio2Protocol | Http11AprProtocol |
| Tomcat 版本 | 从6.0.x开始 | 从8.0.x开始 | 从5.5.x 开始 |
| 支持轮询 | 支持 | 支持 | 支持 |
| 轮询大小 | maxConnections | maxConnections | maxConnections |
| 读取请求标头 | 非阻塞 | 非阻塞 | 非阻塞 |
| 读取请求正文 | 封锁 | 封锁 | 封锁 |
| 编写相应标题和正文 | 封锁 | 封锁 | 封锁 |
| 等待下一个请求 | 不阻塞 | 不阻塞 | 不阻塞 |
| SSL支持 | Java SSL或OpenSSL | Java SSL或OpenSSL | OpenSSL |
| SSL握手 | 不阻塞 | 不阻塞 | 阻塞 |
| 最大连接数 | maxConnections | maxConnections | maxConnections |
JVM 参数
Tomcat 启动命令行中的优化参数,就是 JVM 的优化 。Tomcat 首先跑在 JVM 之上的,因为它的启动其实也只是一个 java 命令行,首先我们需要对这个 JAVA 的启动命令行进行调优。不管是 YGC 还是 Full GC,GC 过程中都会对导致程序运行中中断,正确的选择不同的 GC 策略,调整 JVM、GC 的参数,可以极大的减少由于 GC 工作,而导致的程序运行中断方面的问题,进而适当的提高 Java 程序的工作效率。但是调整 GC 是以个极为复杂的过程,由于各个程序具备不同的特点,如:web 和 GUI 程序就有很大区别(Web可以适当的停顿,但GUI停顿是客户无法接受的),而且由于跑在各个机器上的配置不同(主要 cup 个数,内存不同),所以使用的 GC 种类也会不同。
JVM 参数配置方法
JAVA_OPS 和 CATALINA_OPTS 区别
Tomcat 的启动参数位于安装目录 ${JAVA_HOME}/bin目录下,Linux 操作系统就是 catalina.sh 文件。JAVA_OPTS,就是用来设置 JVM 相关运行参数的变量,还可以在 CATALINA_OPTS 变量中设置。
- JAVA_OPTS:用于当 Java 运行时选项“start”、“stop”或“run”命令执行
- CATALINA_OPTS:用于当 Java 运行时选项“start”或“run”命令执行
首先,在启动 Tomcat 时,任何指定变量的传递方式都是相同的,可以传递到执行“start”或“run”命令中,但只有设定在 JAVA_OPTS 变量里的参数被传递到“stop”命令中。对于 Tomcat 运行过程,可能没什么区别,影响的是结束程序,而不是启动程序。
第二个区别是更微妙,其他应用程序也可以使用 JAVA_OPTS 变量,但只有在 Tomcat 中使用 CATALINA_OPTS 变量。如果你设置环境变量为只使用 Tomcat,最好你会建议使用 CATALINA_OPTS 变量,而如果你设置环境变量使用其它的 Java 应用程序,例如 JBoss,你应该把你的设置放在JAVA_OPTS 变量中。
JVM 参数属性
# 下面列出的是参数示例,参数值需要根据实际情况设置
CATALINA_OPTS="
-server
-Xms6000M
-Xmx6000M
-Xss512k
-XX:NewSize=2250M
-XX:MaxNewSize=2250M
-XX:PermSize=128M
-XX:MaxPermSize=256M
-XX:+AggressiveOpts
-XX:+UseBiasedLocking
-XX:+DisableExplicitGC
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:MaxTenuringThreshold=31
-XX:+CMSParallelRemarkEnabled
-XX:+UseCMSCompactAtFullCollection
-XX:LargePageSizeInBytes=128m
-XX:+UseFastAccessorMethods
-XX:+UseCMSInitiatingOccupancyOnly
-Duser.timezone=Asia/Shanghai
-Djava.awt.headless=true"
常用参数说明
- -server
-server:一定要作为第一个参数,在多个 CPU 时性能佳,还有一种叫 -client 的模式,特点是启动速度比较快,但运行时性能和内存管理效率不高,通常用于客户端应用程序或开发调试,在 32 位环境下直接运行 Java 程序默认启用该模式。Server 模式的特点是启动速度比较慢,但运行时性能和内存管理效率很高,适用于生产环境,在具有 64 位能力的 JDK 环境下默认启用该模式,可以不配置该参数。
- -Xms
-Xms:表示 Java 初始化堆的大小,-Xms 与-Xmx 设成一样的值,避免 JVM 反复重新申请内存,导致性能大起大落,默认值为物理内存的 1/64,默认(MinHeapFreeRatio参数可以调整)空余堆内存小于 40% 时,JVM 就会增大堆直到 -Xmx 的最大限制。
- -Xmx
-Xmx:表示最大 Java 堆大小,当应用程序需要的内存超出堆的最大值时虚拟机就会提示内存溢出,并且导致应用服务崩溃,因此一般建议堆的最大值设置为可用内存的最大值的80%。如何知道我的 JVM 能够使用最大值,使用 java -Xmx512M -version 命令来进行测试,然后逐渐的增大 512 的值,如果执行正常就表示指定的内存大小可用,否则会打印错误信息,默认值为物理内存的 1/4,默认(MinHeapFreeRatio参数可以调整)空余堆内存大于 70% 时,JVM 会减少堆直到-Xms 的最小限制。
- -Xss
-Xss:表示每个 Java 线程堆栈大小,JDK 5.0 以后每个线程堆栈大小为 1M,以前每个线程堆栈大小为 256K。根据应用的线程所需内存大小进行调整,在相同物理内存下,减小这个值能生成更多的线程,但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在 3000~5000 左右。一般小的应用, 如果栈不是很深, 应该是128k 够用的,大的应用建议使用 256k 或 512K,一般不易设置超过 1M,要不然容易出现out ofmemory。这个选项对性能影响比较大,需要严格的测试。
- -XX:NewSize
-XX:NewSize:设置新生代内存大小。
- -XX:MaxNewSize
-XX:MaxNewSize:设置最大新生代新生代内存大小
- -XX:PermSize
-XX:PermSize:设置持久代内存大小
- -XX:MaxPermSize
-XX:MaxPermSize:设置最大值持久代内存大小,永久代不属于堆内存,堆内存只包含新生代和老年代。
- -XX:+AggressiveOpts
-XX:+AggressiveOpts:作用如其名(aggressive),启用这个参数,则每当 JDK 版本升级时,你的 JVM 都会使用最新加入的优化技术(如果有的话)。
- -XX:+UseBiasedLocking
-XX:+UseBiasedLocking:启用一个优化了的线程锁,我们知道在我们的appserver,每个http请求就是一个线程,有的请求短有的请求长,就会有请求排队的现象,甚至还会出现线程阻塞,这个优化了的线程锁使得你的appserver内对线程处理自动进行最优调配。
- -XX:+DisableExplicitGC
-XX:+DisableExplicitGC:在 程序代码中不允许有显示的调用“System.gc()”。每次在到操作结束时手动调用 System.gc() 一下,付出的代价就是系统响应时间严重降低,就和关于 Xms,Xmx 里的解释的原理一样,这样去调用 GC 导致系统的 JVM 大起大落。
- -XX:+UseConcMarkSweepGC
-XX:+UseConcMarkSweepGC:设置年老代为并发收集,即 CMS gc,这一特性只有 jdk1.5 后续版本才具有的功能,它使用的是 gc 估算触发和 heap 占用触发。我们知道频频繁的 GC 会造面 JVM 的大起大落从而影响到系统的效率,因此使用了 CMS GC 后可以在 GC 次数增多的情况下,每次 GC 的响应时间却很短,比如说使用了 CMS GC 后经过 jprofiler 的观察,GC 被触发次数非常多,而每次 GC 耗时仅为几毫秒。
- -XX:+UseParNewGC
-XX:+UseParNewGC:对新生代采用多线程并行回收,这样收得快,注意最新的 JVM 版本,当使用 -XX:+UseConcMarkSweepGC 时,-XX:UseParNewGC 会自动开启。因此,如果年轻代的并行 GC 不想开启,可以通过设置 -XX:-UseParNewGC 来关掉。
- -XX:MaxTenuringThreshold
-XX:MaxTenuringThreshold:设置垃圾最大年龄。如果设置为0的话,则新生代对象不经过 Survivor 区,直接进入老年代。对于老年代比较多的应用(需要大量常驻内存的应用),可以提高效率。如果将此值设置为一 个较大值,则新生代对象会在 Survivor 区进行多次复制,这样可以增加对象在新生代的存活时间,增加在新生代即被回收的概率,减少Full GC的频率,这样做可以在某种程度上提高服务稳定性。该参数只有在串行 GC 时才有效,这个值的设置是根据本地的 jprofiler 监控后得到的一个理想的值,不能一概而论原搬照抄。
- -XX:+CMSParallelRemarkEnabled
-XX:+CMSParallelRemarkEnabled:在使用 UseParNewGC 的情况下,尽量减少 mark 的时间。
- -XX:+UseCMSCompactAtFullCollection
-XX:+UseCMSCompactAtFullCollection:在使用 concurrent gc 的情况下,防止 memoryfragmention,对 live object 进行整理,使 memory 碎片减少。
- -XX:LargePageSizeInBytes
-XX:LargePageSizeInBytes:指定 Java heap 的分页页面大小,内存页的大小不可设置过大, 会影响 Perm 的大小。
- -XX:+UseFastAccessorMethods
-XX:+UseFastAccessorMethods:使用 get,set 方法转成本地代码,原始类型的快速优化。
- -XX:+UseCMSInitiatingOccupancyOnly
-XX:+UseCMSInitiatingOccupancyOnly:只有在 oldgeneration 在使用了初始化的比例后 concurrent collector 启动收集。
- -Duser.timezone=Asia/Shanghai
-Duser.timezone=Asia/Shanghai:设置用户所在时区。
- -Djava.awt.headless=true
-Djava.awt.headless=true:这个参数一般我们都是放在最后使用的,这全参数的作用是这样的,有时我们会在我们的 J2EE 工程中使用一些图表工具如:jfreechart,用于在 web 网页输出 GIF/JPG 等流,在 winodws 环境下,一般我们的 app server 在输出图形时不会碰到什么问题,但是在linux/unix 环境下经常会碰到一个 exception 导致你在 winodws 开发环境下图片显示的好好可是在 linux/unix 下却显示不出来,因此加上这个参数以免避这样的情况出现。
- -Xmn
-Xmn:新生代的内存空间大小,注意:此处的大小是(eden+ 2 survivor space)。与 jmap -heap 中显示的 New gen 是不同的。整个堆大小 = 新生代大小 + 老生代大小 + 永久代大小。在保证堆大小不变的情况下,增大新生代后,将会减小老生代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的 3/8。
- -XX:CMSInitiatingOccupancyFraction
-XX:CMSInitiatingOccupancyFraction:当堆满之后,并行收集器便开始进行垃圾收集,例如,当没有足够的空间来容纳新分配或提升的对象。对于 CMS 收集器,长时间等待是不可取的,因为在并发垃圾收集期间应用持续在运行(并且分配对象)。因此,为了在应用程序使用完内存之前完成垃圾收集周期,CMS 收集器要比并行收集器更先启动。因为不同的应用会有不同对象分配模式,JVM 会收集实际的对象分配(和释放)的运行时数据,并且分析这些数据,来决定什么时候启动一次 CMS 垃圾收集周期。这个参数设置有很大技巧,基本上满足(Xmx-Xmn)(100-CMSInitiatingOccupancyFraction)/100 >= Xmn 就不会出现 promotion failed。例如在应用中 Xmx 是6000,Xmn 是 512,那么 Xmx-Xmn 是 5488M,也就是老年代有 5488M,CMSInitiatingOccupancyFraction=90 说明老年代到 90% 满的时候开始执行对老年代的并发垃圾回收(CMS),这时还 剩 10% 的空间是 548810% = 548M,所以即使 Xmn(也就是新生代共512M)里所有对象都搬到老年代里,548M 的空间也足够了,所以只要满足上面的公式,就不会出现垃圾回收时的 promotion failed,因此这个参数的设置必须与 Xmn 关联在一起。
- -XX:+CMSIncrementalMode
-XX:+CMSIncrementalMode:该标志将开启 CMS 收集器的增量模式。增量模式经常暂停 CMS 过程,以便对应用程序线程作出完全的让步。因此,收集器将花更长的时间完成整个收集周期。因此,只有通过测试后发现正常 CMS 周期对应用程序线程干扰太大时,才应该使用增量模式。由于现代服务器有足够的处理器来适应并发的垃圾收集,所以这种情况发生得很少,用于但 CPU情况。
- -XX:NewRatio
-XX:NewRatio:年轻代(包括 Eden 和两个 Survivor 区)与年老代的比值(除去持久代),-XX:NewRatio=4 表示年轻代与年老代所占比值为 1:4,年轻代占整个堆栈的 1/5,Xms=Xmx 并且设置了 Xmn 的情况下,该参数不需要进行设置。
- -XX:SurvivorRatio
-XX:SurvivorRatio:Eden 区与 Survivor 区的大小比值,设置为 8,表示 2 个 Survivor 区(JVM 堆内存年轻代中默认有 2 个大小相等的 Survivor 区)与 1 个 Eden 区的比值为 2:8,即 1 个 Survivor 区占整个年轻代大小的 1/10。
- -XX:+UseSerialGC
-XX:+UseSerialGC:设置串行收集器。
- -XX:+UseParallelGC
-XX:+UseParallelGC:设置为并行收集器。此配置仅对年轻代有效。即年轻代使用并行收集,而年老代仍使用串行收集。
- -XX:+UseParallelOldGC
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集,JDK6.0 开始支持对年老代并行收集。
- -XX:ConcGCThreads
-XX:ConcGCThreads:早期 JVM 版本也叫-XX:ParallelCMSThreads,定义并发 CMS 过程运行时的线程数。比如 value=4 意味着 CMS 周期的所有阶段都以 4 个线程来执行。尽管更多的线程会加快并发 CMS 过程,但其也会带来额外的同步开销。因此,对于特定的应用程序,应该通过测试来判断增加 CMS 线程数是否真的能够带来性能的提升。如果还标志未设置,JVM 会根据并行收集器中的 -XX:ParallelGCThreads 参数的值来计算出默认的并行 CMS 线程数。
- -XX:ParallelGCThreads
-XX:ParallelGCThreads:配置并行收集器的线程数,即:同时有多少个线程一起进行垃圾回收,此值建议配置与 CPU 数目相等。
- -XX:OldSize
-XX:OldSize:设置 JVM 启动分配的老年代内存大小,类似于新生代内存的初始大小 -XX:NewSize。
以上就是一些常用的配置参数,有些参数是可以被替代的,配置思路需要考虑的是 Java 提供的垃圾回收机制。虚拟机的堆大小决定了虚拟机花费在收集垃圾上的时间和频度。收集垃圾能够接受的速度和应用有关,应该通过分析实际的垃圾收集的时间和频率来调整。假如堆的大小很大,那么完全垃圾收集就会很慢,但是频度会降低。假如您把堆的大小和内存的需要一致,完全收集就很快,但是会更加频繁。调整堆大小的的目的是最小化垃圾收集的时间,以在特定的时间内最大化处理客户的请求。在基准测试的时候,为确保最好的性能,要把堆的大小设大,确保垃圾收集不在整个基准测试的过程中出现。
假如系统花费很多的时间收集垃圾,请减小堆大小。一次完全的垃圾收集应该不超过 3-5 秒。假如垃圾收集成为瓶颈,那么需要指定代的大小,检查垃圾收集的周详输出,研究垃圾收集参数对性能的影响。当增加处理器时,记得增加内存,因为分配能够并行进行,而垃圾收集不是并行的。
设置系统属性
Tomcat 的语言编码,配置起来很慢,要经过多次设置才可以了,否则中文很有可能出现乱码情况。譬如汉字“中”,以 UTF-8 编码后得到的是 3 字节的值 %E4%B8%AD,然后通过 GET 或者 POST 方式把这 3 个字节提交到 Tomcat 容器,如果你不告诉 Tomcat 我的参数是用 UTF-8编码的,那么 Tomcat 就认为你是用 ISO-8859-1 来编码的,而 ISO8859-1(兼容 URI 中的标准字符集 US-ASCII)是兼容 ASCII 的单字节编码并且使用了单字节内的所有空间,因此 Tomcat 就以为你传递的用 ISO-8859-1 字符集编码过的 3 个字符,然后它就用 ISO-8859-1 来解码。
-Djavax.servlet.request.encoding=UTF-8
-Djavax.servlet.response.encoding=UTF-8
-Dfile.encoding=UTF-8
-Duser.country=CN
-Duser.language=zh
常见的java 内存溢出
- java.lang.OutOfMemoryError: Java heap space —-JVM Heap(堆)溢出
JVM 在启动的时候会自动设置 JVM Heap 的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)不可超过物理内存。可以利用 JVM提供的 -Xmn -Xms -Xmx 等选项可进行设置。Heap 的大小是 Young Generation 和 Tenured Generaion 之和。在 JVM 中如果 98% 的时间是用于 GC,且可用的 Heap size 不足 2% 的时候将抛出此异常信息。
解决方法:手动设置 JVM Heap(堆)的大小。
- java.lang.OutOfMemoryError: PermGen space —- PermGen space溢出。
PermGen space 的全称是 Permanent Generation space,是指内存的永久保存区域。为什么会内存溢出,这是由于这块内存主要是被 JVM 存放Class 和 Meta 信息的,Class 在被 Load 的时候被放入 PermGen space 区域,它和存放 Instance 的 Heap 区域不同,sun 的 GC 不会在主程序运行期对 PermGen space 进行清理,所以如果你的 APP 会载入很多 CLASS 的话,就很可能出现 PermGen space 溢出。
解决方法: 手动设置 MaxPermSize 大小
- java.lang.StackOverflowError —- 栈溢出
栈溢出了,JVM 依然是采用栈式的虚拟机,这个和 C 与 Pascal 都是一样的。函数的调用过程都体现在堆栈和退栈上了。调用构造函数的 “层”太多了,以致于把栈区溢出了。通常来讲,一般栈区远远小于堆区的,因为函数调用过程往往不会多于上千层,而即便每个函数调用需要 1K 的空间(这个大约相当于在一个 C 函数内声明了 256 个 int 类型的变量),那么栈区也不过是需要 1MB 的空间。通常栈的大小是 1-2MB 的。 通常递归也不要递归的层次过多,很容易溢出。
解决方法:修改程序。
更多信息,请参考以下文章:
JVM 垃圾回收调优总结
developer.51cto.com/art/201201/…
JVM调优总结:典型配置举例
developer.51cto.com/art/201201/…
JVM基础:JVM参数设置、分析
developer.51cto.com/art/201201/…
JVM 堆内存相关的启动参数:年轻代、老年代和永久代的内存分配
Java 虚拟机–新生代与老年代GC
JVM(Java虚拟机)优化大全和案例实战
JVM内存区域划分Eden Space、Survivor Space、Tenured Gen,Perm Gen解释