骆言 2022-11-25 21:18 采纳率: 91.7%
浏览 158
已结题

数据源 Druid 配置问题,内存泄漏

java tomcat maven war 项目

用 druid 连接 mysql 数据库

运行没毛病,就是报告内存泄漏

十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads 警告: Web应用程序[todo-list]似乎启动了一个名为[Druid-ConnectionPool-Create-2023152835]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[ sun.misc.Unsafe.park(Native Method) java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039) com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2813)]

日志全文

十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Server.服务器版本: Apache Tomcat/8.5.83
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 服务器构建:        Oct 3 2022 21:11:09 UTC
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 服务器版本号:      8.5.83.0
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 操作系统名称:      Windows 10
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: OS.版本:           10.0
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 架构:              amd64
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Java 环境变量:     C:\Program Files\Java\jdk1.8.0_301\jre
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Java虚拟机版本:    1.8.0_301-b09
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: JVM.供应商:        Oracle Corporation
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: CATALINA_BASE:     E:\temp1\tomcat-server-location
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: CATALINA_HOME:     F:\bin_java\apache-tomcat-8.5.83
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数:       -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:52079
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数:       -javaagent:C:\Users\lawsssscat\Desktop\sts-4.16.1.RELEASE\configuration\org.eclipse.osgi\268\0\.cp\lib\javaagent-shaded.jar
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数:       -Dcatalina.base=E:\temp1\tomcat-server-location
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数:       -Dcatalina.home=F:\bin_java\apache-tomcat-8.5.83
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数:       -Dwtp.deploy=E:\temp1\tomcat-server-location\wtpwebapps
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数:       -Djava.endorsed.dirs=F:\bin_java\apache-tomcat-8.5.83\endorsed
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数:       -Dfile.encoding=UTF-8
十一月 25, 2022 8:56:00 下午 org.apache.catalina.core.AprLifecycleListener lifecycleEvent
信息: 在java.library.path:[C:\Program Files\Java\jdk1.8.0_301\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk1.8.0_301\jre\bin;C:/Users/lawsssscat/Desktop/sts-4.16.1.RELEASE//plugins/org.eclipse.justj.openjdk.hotspot.jre.full.win32.x86_64_17.0.4.v20221004-1257/jre/bin/server;C:/Users/lawsssscat/Desktop/sts-4.16.1.RELEASE//plugins/org.eclipse.justj.openjdk.hotspot.jre.full.win32.x86_64_17.0.4.v20221004-1257/jre/bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Git\cmd;C:\Program Files\Git\bin;C:\Program Files\nodejs\;C:\Program Files (x86)\Tencent\微信web开发者工具\dll;C:\Program Files\dotnet\;C:\Program Files\lua;C:\Program Files\luarocks;C:\MinGW\bin;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Program Files\MySQL\MySQL Utilities 1.6\;C:\Program Files\MySQL\MySQL Shell 8.0\bin\;C:\Ruby31-x64\bin;C:\Ruby24-x64\bin;C:\Users\lawsssscat\AppData\Local\Microsoft\WindowsApps;C:\Program Files\qemu;C:\Users\lawsssscat\AppData\Roaming\npm;C:\Users\lawsssscat\AppData\Local\Programs\Microsoft VS Code\bin;C:\Program Files\ffmpeg\bin;E:\nodejs\node_global;C:\Users\lawsssscat\AppData\Local\GitHubDesktop\bin;C:\Users\lawsssscat\AppData\Local\Programs\Python\Python310;C:\Users\lawsssscat\Desktop\cmder;C:\cmake\bin;C:\bash_extend;F:\bin_java\apache-maven-3.8.6\bin;C:\Program Files\Java\jdk1.8.0_301\bin;F:\bin_db\mysql-8.0.31-winx64\bin;;C:\Users\lawsssscat\Desktop\sts-4.16.1.RELEASE;;.]上找不到基于APR的Apache Tomcat本机库,该库允许在生产环境中获得最佳性能
十一月 25, 2022 8:56:00 下午 org.apache.coyote.AbstractProtocol init
信息: 初始化协议处理器 ["http-nio-8080"]
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.Catalina load
信息: Initialization processed in 418 ms
十一月 25, 2022 8:56:00 下午 org.apache.catalina.core.StandardService startInternal
信息: 正在启动服务[Catalina]
十一月 25, 2022 8:56:00 下午 org.apache.catalina.core.StandardEngine startInternal
信息: 正在启动 Servlet 引擎:[Apache Tomcat/8.5.83]
十一月 25, 2022 8:56:00 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
十一月 25, 2022 8:56:01 下午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
警告: 使用[SHA1PRNG]创建会话ID生成的SecureRandom实例花费了[172]毫秒。
十一月 25, 2022 8:56:01 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
十一月 25, 2022 8:56:01 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: 把web 应用程序部署到目录 [E:\temp1\tomcat-server-location\webapps\todo-list-pkg]
十一月 25, 2022 8:56:01 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
十一月 25, 2022 8:56:01 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Web应用程序目录[E:\temp1\tomcat-server-location\webapps\todo-list-pkg]的部署已在[316]毫秒内完成
十一月 25, 2022 8:56:01 下午 org.apache.coyote.AbstractProtocol start
信息: 开始协议处理句柄["http-nio-8080"]
十一月 25, 2022 8:56:01 下午 org.apache.catalina.startup.Catalina start
信息: Server startup in 1174 ms
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
十一月 25, 2022 8:56:06 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
十一月 25, 2022 8:56:52 下午 org.apache.catalina.core.StandardContext reload
信息: 已开始重新加载名为[/todo-list]的上下文
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesJdbc
警告: Web应用程序 [todo-list] 注册了JDBC驱动程序 [com.alibaba.druid.proxy.DruidDriver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesJdbc
警告: Web应用程序 [todo-list] 注册了JDBC驱动程序 [com.mysql.jdbc.Driver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads
警告: Web应用程序[todo-list]似乎启动了一个名为[Abandoned connection cleanup thread]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
 java.lang.Object.wait(Native Method)
 java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
 com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:43)]
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads
警告: Web应用程序[todo-list]似乎启动了一个名为[Druid-ConnectionPool-Create-2023152835]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2813)]
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads
警告: Web应用程序[todo-list]似乎启动了一个名为[Druid-ConnectionPool-Destroy-2023152835]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
 java.lang.Thread.sleep(Native Method)
 com.alibaba.druid.pool.DruidDataSource$DestroyConnectionThread.run(DruidDataSource.java:2913)]
十一月 25, 2022 8:56:52 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
十一月 25, 2022 8:56:52 下午 org.apache.catalina.core.StandardContext reload
信息: 已完成重新加载名为[/todo-list]的上下文
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
十一月 25, 2022 9:05:20 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited

查看数据库连接,确实有问题:

  1. 每次连接数据库会创建10个连接(这应该正常,线程池)
  2. 长时间(大概10min)不与数据库交互,数据库连接并没有断开(这也没啥。问题是下面)
  3. 一段时间后,再次访问数据库,会创建新的10个连接。问题是,旧的10个连接并不会关闭!
  4. 程序长时间运行的结果是,创建了一堆与数据库的连接,而只有其中10个在工作。
  5. 直到程序关闭,数据库连接才断开

img

连接配置

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.1.7777:111111/xxxxx
username=bbbb
password=xxxxx
initialSize=10
maxActive=20
maxWait=10000

获取、销毁连接代码

package com.lawsssscat.web.util;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import com.alibaba.druid.pool.DruidDataSourceFactory;

/**
 * 
 * 1. 从数据源获取数据库连接
 * 2. 将数据源绑定到ThreadLocal
 * 3. 释放线程时和本地线程解除绑定
 * 
 * @author lawsssscat
 *
 */
public class JDBCUtils {

    // 数据源成员变量设置为静态资源,单例性
    private static DataSource dataSource;
    
    // 由于ThreadLocal对象需要作为绑定数据时的key从线程key-value对中获取数据,因此,要保证唯一性
    // 加static声明为静态资源既可保证唯一性
    final private static ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();
    
    // 在静态代码块中初始化数据源
    static {
        // 从 jdbc.properties 文件中读取数据库的信息
        // 基于WEB-INFO/classes(类路径根目录)获取配置文件,保证可移植性
        
        // 1. 获取当前的类加载器
        ClassLoader classLoader = JDBCUtils.class.getClassLoader();
        // 2. 通过类加载器对象从类路径根目录下读取文件
        InputStream stream = classLoader.getResourceAsStream("jdbc.properties");
        // 3. 使用Properties类封装属性文件中的数据
        Properties properties = new Properties();
        try {
            properties.load(stream);
            //4. 根据Properties对象(已封装了数据库连接信息)
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
            // 立即终止
            throw new RuntimeException(e);
        }
    }
    
    public static Connection getConnection() throws SQLException {
        Connection connection = connectionThreadLocal.get();
        if(connection==null) {
            connection = dataSource.getConnection();
            connectionThreadLocal.set(connection);
        }
        return connection;
    }
    
    public static void releaseConnection() throws SQLException {
        Connection connection = connectionThreadLocal.get();
        if(connection != null) {
            // 将当前数据库连接从当前线程上移除
            connectionThreadLocal.remove();
            // 放后面,因为可能抛出错误!
            connection.close();
        }
    }
}

filter 中获取连接

package com.lawsssscat.web.filter;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import com.lawsssscat.web.util.BooleanHelper;
import com.lawsssscat.web.util.JDBCUtils;
import com.lawsssscat.web.util.WebHelper;
import com.lawsssscat.web.util.WebVariable;

public class TransactionFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        // 静态资源跳过处理
        if(BooleanHelper.isTrue(WebHelper.getRequestVariable(WebVariable.REQUEST_STATIC_RESOURCE))) {
            chain.doFilter(request, response);
            return;
        }
        
        // 获取数据库连接
        // ⭐️ 重要:需要保证参与事务的多个数据库操作(SQL语句)使用的是同一个数据库连接
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
            
            // 取消自动提交
            connection.setAutoCommit(false);
            
            // 业务处理
            chain.doFilter(request, response);
            
            // 业务处理成功,提交事务
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                // 业务处理失败,回滚事务
                connection.rollback();
            } catch (SQLException e1) {
                // TODO mark
                e1.printStackTrace();
            }
            
        } finally {
            try {
                JDBCUtils.releaseConnection();
            } catch (SQLException e) {
                // TODO mark
                e.printStackTrace();
            }
        }
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }

}
  • 写回答

2条回答 默认 最新

  • 骆言 2022-11-28 19:53
    关注

    啥也没改,把druid退回到更多人用版本,好像就没有这种情况了:

    1.2.8 => 1.1.10

    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
            <dependency>  
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.10</version>
            </dependency>
    

    猜是1.2.8版本的超时关连接逻辑有问题

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 12月6日
  • 已采纳回答 11月28日
  • 修改了问题 11月25日
  • 修改了问题 11月25日
  • 展开全部

悬赏问题

  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀