http://71.oopspy.com/?p=2230
参考:http://tomcat.apache.org/tomcat-8.5-doc/config/http.html
连接器选择:
cat catalina.sh
-
- #!/bin/sh
- JAVA_HOME="/opt/programs/jdk_1.8.0_111"
- CPU_N=`cat /proc/cpuinfo| grep "processor"| wc -l`
- JMX_PORTS=`grep "jmx.port" $CATALINA_BASE/conf/catalina.properties | cut -d= -f2`
- if [ "$1"x = "start"x ] ; then
- JMX_OPTS="-Dcom.sun.management.jmxremote.port=$JMX_PORTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"
- else
- echo "stop: not to bind jmx port"
- fi
- JAVA_OPTS="
- -server
- -Xmx1024M
- -Xms1024M
- -Xmn256M
- -XX:MetaspaceSize=256m
- -XX:MaxMetaspaceSize=512m
- -Xss512K
- -XX:+ExplicitGCInvokesConcurrent
- -XX:+UseConcMarkSweepGC
- -XX:+UseParNewGC
- -XX:ParallelGCThreads=$CPU_N
- -XX:+CMSParallelRemarkEnabled
- -XX:+CMSClassUnloadingEnabled
- -XX:LargePageSizeInBytes=128M
- -XX:+UseFastAccessorMethods
- -XX:CMSInitiatingOccupancyFraction=80
- -XX:SoftRefLRUPolicyMSPerMB=0
- -XX:+PrintGC
- -XX:+PrintGCDetails
- -XX:+PrintGCTimeStamps
- -XX:+PrintGCDateStamps
- -XX:+PrintHeapAtGC
- -XX:+PrintGCApplicationStoppedTime
- -Xloggc:$CATALINA_BASE/logs/`date +%Y%m%d%H%M%S`_gc.log
- -XX:+HeapDumpOnOutOfMemoryError"
- JAVA_OPTS="$JAVA_OPTS $JMX_OPTS -Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.EPollSelectorProvider"
- ......
#上述的配置效果:
系统响应时间增快
JVM回收速度增快同时又不影响系统的响应率
JVM内存最大化利用
线程阻塞情况最小化
nio支持epoll,启用epoll对并发idle connection会有大幅度的性能提升
cat server.xml
-
- <?xml version='1.0' encoding='utf-8'?>
- <Server port="${shutdown.port}" 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" />
- <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
- <Listener className="org.apache.catalina.core.JasperListener" />
- <!-- 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" />
- <GlobalNamingResources>
- <Resource name="UserDatabase" auth="Container"
- type="org.apache.catalina.UserDatabase"
- description="User database that can be updated and saved"
- factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
- pathname="conf/tomcat-users.xml" />
- </GlobalNamingResources>
- <Service name="Catalina">
- <!--The connectors can use a shared executor, you can define one or more named thread pools-->
- <Executor name="tomcatThreadPool"
- namePrefix="catalina-exec-"
- maxThreads="1500"
- minSpareThreads="50"/>
- <!-- A "Connector" represents an endpoint by which requests are received
- and responses are returned. Documentation at :
- Java HTTP Connector: /docs/config/http.html
- Java AJP Connector: /docs/config/ajp.html
- APR (HTTP/AJP) Connector: /docs/apr.html
- Define a non-SSL/TLS HTTP/1.1 Connector on port 8080-->
- <Connector URIEncoding="UTF-8" executor="tomcatThreadPool"
- asyncTimeout="900000"
- maxConnections="40000"
- port="${http.port}"
- server="nginx"
- protocol="org.apache.coyote.http11.Http11Nio2Protocol"
- enableLookups="false"
- maxKeepAliveRequests="20"
- connectionTimeout="40000"
- acceptCount="200"
- maxThreads="20000"
- disableUploadTimeout="true"
- redirectPort="{https.port}" />
- <Connector URIEncoding="UTF-8" executor="tomcatThreadPool"
- asyncTimeout="900000"
- maxConnections="40000"
- port="${ajp.port}"
- protocol="org.apache.coyote.ajp.AjpNio2Protocol"
- enableLookups="false"
- maxKeepAliveRequests="20"
- connectionTimeout="40000"
- acceptCount="200"
- maxThreads="20000"
- disableUploadTimeout="true"
- redirectPort="{https.port}" />
- <Engine name="Catalina"
- defaultHost="localhost">
- <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
- resourceName="UserDatabase"/>
- <Host name="localhost" appBase="webapps"
- unpackWARs="false" autoDeploy="false"
- xmlValidation="false" xmlNamespaceAware="false">
- <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
- prefix="access." suffix=".log" pattern="%h %l %u %t %r %s %b %D" resolveHosts="false"/>
- </Host>
- </Engine>
- </Service>
- </Server>
说明:
1、tomcat8 nio最大连接数配置
使用maxConnections,默认10000。
2、JVM的GC日志的主要参数
-XX:+PrintGC 输出GC日志
-XX:+PrintGCDetails 输出GC的详细日志
-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
-XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
-XX:+PrintGCApplicationStoppedTime // 输出GC造成应用暂停的时间
-Xloggc:../logs/gc.log 日志文件的输出路径
-XX:+HeapDumpOnOutOfMemoryError //发生OOM的时候自动dump堆栈方便分析
3、如何看垃圾收集策略
jmap -heap 其他:jmap -clstats
4、如何实时看堆内存的使用情况
jstat -gcutil [pid] [interval] //实时打印gc情况以及各代内存占用比例
常用命令
jstat -gcutil -h10 vmid1000
统计gc信息统计
S0 — Heap上的 Survivor space 0 区已使用空间的百分比
S1 — Heap上的 Survivor space 1 区已使用空间的百分比
E — Heap上的 Eden space 区已使用空间的百分比
O — Heap上的 Old space 区已使用空间的百分比
M — 元数据区已使用空间的百分比
YGC — 从应用程序启动到采样时发生 Young GC 的次数
YGCT– 从应用程序启动到采样时 Young GC 所用的时间(单位秒)
FGC — 从应用程序启动到采样时发生 Full GC 的次数
FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒)
jmap -dump:format=b,file=f1 //dump内存到二进制文件
jmap -histo [pid] //按占大小倒序列出内存中的实例类型
-
- jstat –options参看可选的option:
- -class //查看类加载情况的统计
- -compiler //查看HotSpot中即时编译器编译情况的统计
- -gc
- -gccapacity //新生代、老生代及持久代的存储容量情况
- -gccause
- -gcmetacapacity //查看元数据区的容量
- -gcnew //新生代垃圾收集的情况
- -gcnewcapacity //新生代的存储容量情况
- -gcold
- -gcoldcapacity
- -gcutil
- -printcompilation // HotSpot编译方法的统计
5、如何查看线程栈
jstack 进程PID
这样可以列出当前pid对应jvm的所有线程栈描述,描述主要包括了每个线程的状态以及堆栈内各栈帧的方法全限定名,代码位置。注意这只是为了可阅读性,并不是说栈里存着的就是这些字符串。
6、JVM内存模型三区域
线程栈区—它压入的每个栈帧(Stack Frame)是程序指令以及局部变量表,每个方法调用对应一个栈帧。局部变量表包括各种基本数据类型:boolean、byte、char、short、int、float、long、double以及对象的引用。我们需要注意到每个线程都有独立的栈并且是互相隔离的。
JAVA堆区—是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
静态方法区—又称为永久代(Perm Generation)。它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。常见的JVM配置包括:-XX:MaxPermSize=512m(JDK8中移除了),JDK8中用metaspace代替permsize,因此在许多我们设置permsize大小的地方需要修改配置为metaspace
将-XX:PermSize=xxm;-XX:MaxPermSize=yym;修改为:-XX:MetaspaceSize=xxm;-XX:MaxMetaspaceSize=yym;
JDK 8的HotSpot JVM现在使用的是本地内存来表示类的元数据,这个区域就叫做元空间。
-
- 元空间的特点:
- 充分利用了Java语言规范中的好处:类及相关的元数据的生命周期与类加载器的一致。
- 每个加载器有专门的存储空间
- 只进行线性分配
- 不会单独回收某个类
- 省掉了GC扫描及压缩的时间
- 元空间里的对象的位置是固定的
- 如果GC发现某个类加载器不再存活了,会把相关的空间整个回收掉
-
- 元空间的内存分配模型:
- 绝大多数的类元数据的空间都从本地内存中分配
- 用来描述类元数据的类也被删除了
- 分元数据分配了多个虚拟内存空间
- 给每个类加载器分配一个内存块的列表。块的大小取决于类加载器的类型; sun/反射/***对应的类加载器的块会小一些
- 归还内存块,释放内存块列表
- 一旦元空间的数据被清空了,虚拟内存的空间会被回收掉
- 减少碎片的策略
元空间的调优:
使用-XX:MaxMetaspaceSize参数可以设置元空间的最大值,默认是没有上限的,也就是说你的系统内存上限是多少它就是多少。-XX:MetaspaceSize选项指定的是元空间的初始大小,如果没有指定的话,元空间会根据应用程序运行时的需要动态地调整大小。
MaxMetaspaceSize的调优
-XX:MaxMetaspaceSize={unlimited}
元空间的大小受限于你机器的内存
限制类的元数据使用的内存大小,以免出现虚拟内存切换以及本地内存分配失败。如果怀疑有类加载器出现泄露,应当使用这个参数;32位机器上,如果地址空间可能会被耗尽,也应当设置这个参数。
元空间的初始大小是21M——这是GC的初始的高水位线,超过这个大小会进行Full GC来进行类的回收。
如果启动后GC过于频繁,请将该值设置得大一些
可以设置成和持久代一样的大小,以便推迟GC的执行时间
使用-XX:MaxMetaspaceSize参数可以设置元空间的最大值,默认是没有上限的,也就是说你的系统内存上限是多少它就是多少。-XX:MetaspaceSize选项指定的是元空间的初始大小,如果没有指定的话,元空间会根据应用程序运行时的需要动态地调整大小。
MaxMetaspaceSize的调优
-XX:MaxMetaspaceSize={unlimited}
元空间的大小受限于你机器的内存
限制类的元数据使用的内存大小,以免出现虚拟内存切换以及本地内存分配失败。如果怀疑有类加载器出现泄露,应当使用这个参数;32位机器上,如果地址空间可能会被耗尽,也应当设置这个参数。
元空间的初始大小是21M——这是GC的初始的高水位线,超过这个大小会进行Full GC来进行类的回收。
如果启动后GC过于频繁,请将该值设置得大一些
可以设置成和持久代一样的大小,以便推迟GC的执行时间。
7、堆划分为新生代和老年代
然后新生代又可以划分为一个Eden区和两个Survivor(幸存)区。
按照规定,新对象会首先分配在Eden中(如果对象过大,比如大数组,将会直接放到老年代)。在GC中,Eden中的对象会被移动到survivor中,直至对象满足一定的年纪(定义为熬过minor GC的次数),会被移动到老年代。
新生代 ( Young )与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 )
默认的,Eden : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 ),
即: Eden = 8/10 的新生代空间大小,from = to = 1/10 的新生代空间大小。
8、关于晋升到老年代的条件
对象有两种可能会进入old区:
存活对象过多。在s1和s2都已经溢出了。如果从eden迁往survior区时,发现放不下,则直接进入old Gen
从eden到s区来回拷贝次数达到一定的数量,总没有回收掉,进入old区。(从eden到survior1迁到,引用持有中,s1中放不下新迁对象,则清理s1,存活对象,晋升入s2;再下次或继续迁移,就把s2中的。准备说,可能是,这些个对象从s1<->s2来回拷贝一定次数后,会进入old Gen)。这块Servivor Space 调整合适的存活次数 Threshold 通过-XX:MaxTenuringThreshold。但也只是一个建议,最终仍由虚拟机决定。
9、并发数参数优化
线程数限制并发数
1)、系统最大线程数:
/proc/sys/kernel/threads-max 与 /proc/sys/vm/max_map_count 定义了总的最大线程数
mmap这个system_call的最大数量(也就是从内存方面限制了线程数)
2)、理论上我们能分配给线程的内存除以单个线程占用的内存就是最大线程数。所以说对Java进程来讲,既然分配给了堆,栈和静态方法区(或叫永久代,perm区),我们可以大致认为:
线程数 = (系统空闲内存-堆内存(-Xms, -Xmx)- perm区内存(-XX:MaxPermSize)) / 线程栈大小(-Xss)
注意这只是帮助我们树立一个概念,实际上还有许多因素影响。
栈的大小还影响到一个就是如果单个栈超过了这个大小,就会抛出StackOverflowError,一般来说递归调用是常见的原因。