我正在运行一个springboot项目,我有一个调用sqlserver数据库的方法,它连接良好并返回结果。
但是,当我开始重新部署更新时,这会出现在tomcat日志中:
==> catalina.2021-04-25.log <==
25-Apr-2021 09:05:45.307 WARNING [Catalina-utility-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [ciamdev] registered the JDBC driver [com.microsoft.sqlserver.jdbc.SQLServerDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
25-Apr-2021 09:05:45.309 WARNING [Catalina-utility-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ciamdev] appears to have started a thread named [mssql-jdbc-shared-timer-core-0] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
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)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:748)
25-Apr-2021 09:05:45.310 WARNING [Catalina-utility-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ciamdev] appears to have started a thread named [HikariPool-113 housekeeper] but has failed to stop it. This is very likely to create a memory leak.
25-Apr-2021 09:05:45.312 WARNING [Catalina-utility-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ciamdev] appears to have started a thread named [HikariPool-113 connection adder] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
基本上有四个主要事件:
com.microsoft.sqlserver.jdbc.SQLServerDriver is forcibly removed
mssql-jdbc-shared-timer-core-0 thread was unable to shut down
HikariPool-113 housekeeper thread was unable to shut down
HikariPool-113 connection adder thread was unable to shut down
当我不断调用数据库,然后重新部署时,hikaripool线程开始成倍增加。
经过一番研究,我决定尝试一种涉及servletcontextlistener的解决方案
我现在发布相关信息/代码:
这是tomcat版本:
Using CATALINA_BASE: /apps/tomcat/apache-tomcat-9.0.34
Using CATALINA_HOME: /apps/tomcat/apache-tomcat-9.0.34
Using CATALINA_TMPDIR: /apps/tomcat/apache-tomcat-9.0.34/temp
Using JRE_HOME: /usr
Using CLASSPATH: /apps/tomcat/apache-tomcat-9.0.34/bin/bootstrap.jar:/apps/tomcat/apache-tomcat-9.0.34/bin/tomcat-juli.jar
Server version: Apache Tomcat/9.0.34
Server built: Apr 3 2020 12:02:52 UTC
Server number: 9.0.34.0
OS Name: Linux
OS Version: 3.10.0-1160.24.1.el7.x86_64
Architecture: amd64
JVM Version: 1.8.0_275-b01
JVM Vendor: Red Hat, Inc.
Apache Maven version 3.8.1
以下是我的pom.xml依赖项(我在另一篇文章中添加了hikaricp exclusions标记):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
我创建了一个db类,在这个类中我示例化了jdbctemplate并添加了数据源,还实现了servletcontextlistener,我敢肯定我搞砸了整个类,下面是这个类:
public class Db implements ServletContextListener {
String message;
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
message = "contextInitialized\n\n";
System.out.println("contextInitialized Server stopped");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
message += "contextDestroyed\n\n";
System.out.println("contextDestroyed Server stopped");
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
} catch (SQLException e) {
message += "ERROR(contextDestroyed): " + Utils.getStackTrace(e);
}
}
}
JdbcTemplate jdbcTemplate;
public Db() {
jdbcTemplate = new JdbcTemplate(sqlServerDataSource());
}
@Bean(destroyMethod = "shutdownNow")
private DataSource sqlServerDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url(
"jdbc:sqlserver://sbserver.net;databaseName=gg"
);
dataSourceBuilder.username("user");
dataSourceBuilder.password("pass");
return dataSourceBuilder.build();
}
public String runSome() {
message = "From runSome: \n\n";
try {
message += "trying to execute jdbcTemplate...\n";
String sql = "select * from gg.objecttypes";
List<ObjectType> objectTypes = jdbcTemplate.query(
sql,
new BeanPropertyRowMapper(ObjectType.class)
);
message += "\n\n";
for (final ObjectType objectType : objectTypes) {
message +=
objectType.getId() + " :: " + objectType.getObjecttype() + "\n";
}
message +=
"::executed jdbcTemplate! " + objectTypes.size() + "\n";
} catch (Exception e) {
message += "ERROR(runSome): " + Utils.getStackTrace(e);
}
return message;
}
}
我甚至不确定contextinitialized和contextdestroyed方法是否正在执行。
然后我可以从我的控制器调用该方法:
@GetMapping(value = "/admin/user-health")
public String userHealth() {
String message = "From userHealth: \n\n";
try {
message += "trying to execute db.runSome()...\n";
Db db = new Db();
message += db.runSome();
message += "executed db.runSome()!\n";
} catch (Exception e) {
message += "ERROR(userHealth): " + Utils.getStackTrace(e);
}
return message;
}
同样,它工作正常,我从数据库得到结果。虽然最终我得到了一个连接超时。
问题是内存泄漏,因为线程永远不会死,我认为我没有用户。
我怎样才能解决这个问题?
暂无答案!
目前还没有任何答案,快来回答吧!