MacOS下Tomcat 7.0.99调用Web服务后崩溃问题求助
解决Tomcat 7.0.99调用后崩溃及内存泄漏问题
从你贴的catalina.out日志来看,Tomcat崩掉的核心原因是你的Web应用在停止时一堆资源没清理干净,引发了内存泄漏,最终把整个Tomcat进程带崩了。下面针对日志里的每个问题给你具体的修复办法:
1. 搞定JDBC驱动未注销的问题
日志里提示com.mysql.jdbc.Driver没在Web应用停掉的时候注销,虽然Tomcat已经帮你强制注销了,但这只是临时救急,得从根源解决:
- 推荐方案:用Tomcat全局数据源管理驱动
- 把MySQL驱动包
mysql-connector-java-x.x.x.jar放到Tomcat的lib目录下,别再塞到Web应用的WEB-INF/lib里了——这样驱动由Tomcat的全局类加载器管理,应用停止时Tomcat会自动处理注销。 - 在Tomcat的
conf/context.xml里配置全局数据源,示例代码:<Resource name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource" maxTotal="100" maxIdle="30" maxWaitMillis="10000" username="你的数据库用户名" password="你的数据库密码" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/你的数据库名"/> - 在Web应用的
WEB-INF/web.xml里引用这个数据源:<resource-ref> <description>数据库连接</description> <res-ref-name>jdbc/MyDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
- 把MySQL驱动包
- 备选方案:手动注销驱动
如果必须在Web应用里自己管驱动,就在ServletContextListener的contextDestroyed方法里加这段代码,在应用停止时手动注销:Enumeration<Driver> drivers = DriverManager.getDrivers(); while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); // 只注销当前应用类加载器加载的驱动 if (driver.getClass().getClassLoader().equals(getClass().getClassLoader())) { try { DriverManager.deregisterDriver(driver); } catch (SQLException e) { e.printStackTrace(); } } }
2. 清理那些没停掉的线程
日志里列了一堆没停的线程:Thread-2、MySQL Statement Cancellation Timer、Exec系列、OkHttp和Okio的线程,逐个处理:
- 自定义线程(Thread-2):如果是你自己代码里创建的线程,一定要在应用停掉的时候手动中断并等它结束:
- 把线程的引用存起来,在
contextDestroyed里调用thread.interrupt(),再用thread.join()等它终止。 - 线程内部要写响应中断的逻辑,比如循环里检查
Thread.currentThread().isInterrupted(),收到中断信号就退出。
- 把线程的引用存起来,在
- MySQL相关线程:确保用的是连接池(比如Tomcat自带的JDBC Pool),别手动创建连接又不关闭。连接池在应用停止时会自动关掉所有连接,相关线程也会跟着终止。
- Exec系列线程:如果用了
ExecutorService创建线程池,在应用停止时必须调用executorService.shutdown()或者executorService.shutdownNow()来终止线程池,别让它一直跑着。 - OkHttp/Okio线程:OkHttp的连接池默认会回收空闲连接,但如果是你自己创建的OkHttp客户端,在应用停止时要主动关闭:
okHttpClient.dispatcher().executorService().shutdown(); okHttpClient.connectionPool().evictAll();
3. 清理ThreadLocal里的残留引用
日志里说AndroidDriver和AppiumDriverLocalService的ThreadLocal没清理,这会让线程一直拿着Web应用的类加载器引用,直接导致内存泄漏:
- 用完ThreadLocal之后,一定要手动调用
threadLocal.remove()释放引用!比如在请求处理完之后、Servlet的destroy方法里,或者线程池任务执行完的finally块里。 - 如果是在Web请求线程里用的ThreadLocal,最好写个Filter统一处理:在
doFilter的finally块里调用threadLocal.remove(),不管请求成功失败都能清理。
4. Tomcat 7.0.99的额外配置优化
Tomcat 7对资源泄漏的检测特别严,你可以调整点配置来优化:
- 打开
conf/catalina.properties,添加或修改这些配置:# 临时调试可以关掉ThreadLocal泄漏检测(不建议长期关) org.apache.catalina.loader.WebappClassLoaderBase.threadLocalLeakPrevention = false # 给线程清理加个超时时间,默认可能太短 org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreadsTimeout = 5000 - 确保MacOS上用的JDK版本符合要求,Tomcat 7.0.99建议用JDK 7及以上,别用系统自带的旧版本JDK。
按上面的步骤一个个修复完,重新部署应用再测试,应该就能解决首次调用后Tomcat崩溃的问题了。
内容的提问来源于stack exchange,提问作者New Person
相关产品推荐
相关产品推荐

