You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MacOS下Tomcat 7.0.99调用Web服务后崩溃问题求助

解决Tomcat 7.0.99调用后崩溃及内存泄漏问题

从你贴的catalina.out日志来看,Tomcat崩掉的核心原因是你的Web应用在停止时一堆资源没清理干净,引发了内存泄漏,最终把整个Tomcat进程带崩了。下面针对日志里的每个问题给你具体的修复办法:


1. 搞定JDBC驱动未注销的问题

日志里提示com.mysql.jdbc.Driver没在Web应用停掉的时候注销,虽然Tomcat已经帮你强制注销了,但这只是临时救急,得从根源解决:

  • 推荐方案:用Tomcat全局数据源管理驱动
    1. 把MySQL驱动包mysql-connector-java-x.x.x.jar放到Tomcat的lib目录下,别再塞到Web应用的WEB-INF/lib里了——这样驱动由Tomcat的全局类加载器管理,应用停止时Tomcat会自动处理注销。
    2. 在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/你的数据库名"/>
      
    3. 在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>
      
  • 备选方案:手动注销驱动
    如果必须在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):如果是你自己代码里创建的线程,一定要在应用停掉的时候手动中断并等它结束:
    1. 把线程的引用存起来,在contextDestroyed里调用thread.interrupt(),再用thread.join()等它终止。
    2. 线程内部要写响应中断的逻辑,比如循环里检查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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 16:47:44