1. 诊断内存溢出根源
首先需要确认Tomcat内存溢出的具体类型(如堆内存、元空间、线程数等),这是解决问题的关键。
catalina.out、localhost.log等日志文件,搜索OutOfMemoryError相关错误(如java.lang.OutOfMemoryError: Java heap space、java.lang.OutOfMemoryError: Metaspace、java.lang.OutOfMemoryError: unable to create new native thread),明确溢出类型。jmap命令生成堆转储文件(如jmap -dump:format=b,file=/tmp/heap.hprof <Tomcat_PID>),再用Eclipse MAT、VisualVM等工具分析内存中占用最大的对象(如未释放的集合、缓存、ThreadLocal等),定位内存泄漏点。2. 调整JVM内存参数(针对堆/元空间溢出)
Linux下Tomcat的JVM参数通过bin/catalina.sh文件配置(建议在cygwin=false之上添加),根据溢出类型调整对应参数:
-Xms)和最大堆(-Xmx)大小(建议设为物理内存的1/4~1/2,且两者值相等,避免频繁GC)。例如:JAVA_OPTS="-server -Xms2g -Xmx4g -Xss256k"
其中-server启用服务器模式(提升性能),-Xss设置线程栈大小(默认1MB,可适当减小至256K~512K以节省内存)。-XX:MaxMetaspaceSize参数(如-XX:MaxMetaspaceSize=512m),避免元空间无限增长。-XX:PermSize)和最大大小(-XX:MaxPermSize),例如:JAVA_OPTS="-server -Xms1g -Xmx2g -XX:PermSize=256m -XX:MaxPermSize=512m"
注意:Java 8及以上版本无需配置此参数。3. 优化线程池配置(针对线程数耗尽)
若日志中出现unable to create new native thread,说明线程数超过系统或Tomcat限制,需调整server.xml中的线程池参数:
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="500" <!-- 最大线程数(默认200,根据并发量调整) -->
minSpareThreads="50" <!-- 最小空闲线程数 -->
acceptCount="200" <!-- 等待队列长度(默认100,队列满则拒绝请求)" />
同时,检查操作系统级别的线程限制(通过ulimit -u查看),若需调整可修改/etc/security/limits.conf,添加:
tomcat hard nproc 65535
tomcat soft nproc 65535
(将tomcat替换为运行Tomcat的用户)。
4. 检查文件句柄限制(针对文件描述符耗尽)
若应用频繁打开文件或数据库连接未关闭,可能导致Too many open files错误,需调整文件句柄限制:
ulimit -n(默认通常为1024,较小)。ulimit -n 65535(仅当前会话有效)。/etc/security/limits.conf,添加:tomcat hard nofile 65535
tomcat soft nofile 65535
并修改/etc/pam.d/common-session和/etc/pam.d/common-session-noninteractive,添加:session required pam_limits.so
重启Tomcat使配置生效。5. 优化应用代码与连接池
try-with-resources语句确保资源释放;避免在静态集合中缓存大量对象(如静态Map),及时清理无用对象。maxActive(最大连接数,默认100,可根据数据库性能增加至200~500)、maxIdle(最大空闲连接数,默认8~16)、minIdle(最小空闲连接数,默认0~5)等参数,避免连接泄漏(设置removeAbandonedOnBorrow=true、removeAbandonedTimeout=300自动回收闲置连接)。6. 监控与持续调优
JAVA_OPTS中添加-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/tomcat/gc.log,记录GC详情,通过分析GC频率和耗时(如Full GC频繁说明堆内存不足),进一步调整内存参数。