CentOS Tomcat日志中内存泄漏的诊断与解决指南
Tomcat日志(主要为catalina.out)是发现内存泄漏的第一线索,需重点关注两类信息:
java.lang.OutOfMemoryError(如Java heap space、Metaspace溢出)或频繁的Full GC记录(如[GC (Allocation Failure) ... Full GC),提示内存资源不足。Too many open files)或数据库连接超报错,可能是内存泄漏的间接表现(如线程未回收、连接未关闭)。除日志外,需借助工具实时监控内存状态:
top -p $(pgrep -f tomcat)查看Tomcat进程的内存占用(RES列),若内存持续增长且不回落,可能存在泄漏;jstat -gcutil $(pgrep -f tomcat) 1000可监控GC情况(FGC列表示Full GC次数,O列表示老年代使用率,频繁Full GC且O居高不下是典型泄漏特征)。若初步诊断怀疑内存泄漏,需生成堆转储文件(Heap Dump)捕获内存快照,通过工具分析泄漏根源:
生成堆转储:使用jmap命令(需Tomcat进程ID,可通过pgrep -f tomcat获取),例如:
jmap -dump:format=b,file=/tmp/heapdump.hprof $(pgrep -f tomcat)
此命令会生成二进制堆转储文件,包含所有内存对象的引用关系。
分析堆转储:推荐使用Eclipse MAT(Memory Analyzer Tool),导入堆转储文件后可快速识别:
byte[]、HashMap等大对象);结合Tomcat特性,内存泄漏多由以下原因导致:
Connection)、文件流(InputStream)、网络连接等未在finally块中关闭,导致资源长期驻留内存。static Map)的生命周期与应用一致,若不断向其中添加对象(如缓存未设置过期时间),会导致对象无法被GC回收。ThreadLocal变量存储在Thread对象中,若线程池中的线程未调用remove()方法清理,会导致线程复用时对象堆积(如用户Session未清除)。javassist动态创建类)或未正确释放类加载器(如Web应用重新部署时未清理旧类加载器),导致元空间(Metaspace)溢出。修复代码问题:
try-with-resources或finally块关闭;LinkedHashMap的removeEldestEntry方法);ThreadLocal时,在finally块中调用remove()方法;classLoader.unloadClass())。调整JVM参数:
-Xms1024m -Xmx2048m,避免频繁Full GC);-XX:+UseG1GC,提升GC效率);-XX:MaxMetaspaceSize=256m,防止元空间溢出)。监控与预防:
org.apache.catalina.connector.Request内存泄漏问题)。