【发布时间】:2014-02-25 23:23:35
【问题描述】:
我正在使用
构建一个相对简单的网络应用程序- spring-mvc 3.2.0
- spring-jpa 1.2.0
- jpa 2.0
- 休眠 3.6
- MySql 5.6(使用mysql jdbc驱动5.1.28)
我自己不初始化连接,只使用自动装配的存储库来读取或写入实体。
问题:每次:
- 应用已停止(重新部署等)
- 用户会话过期
我在 tomcat 服务器和以下 catalina 日志上遇到内存泄漏:
Feb 02, 2014 1:31:12 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: The web application [/test] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
Feb 02, 2014 1:31:12 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/test] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.
Feb 02, 2014 1:31:12 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
SEVERE: The web application [/test] created a ThreadLocal with key of type [org.springframework.core.NamedThreadLocal] (value [Transactional resources]) and a value of type [java.util.HashMap] (value [{public abstract java.util.List org.springframework.data.jpa.repository.JpaRepository.findAll()=java.lang.Object@632cc9ed, public abstract java.util.List data.repository.QuestionRepository.findAllNonDisabled()=java.lang.Object@632cc9ed, public abstract java.util.List data.repository.AnswerRepository.findAllAnswersForUserAndGameOrderBySortIndex(int,int)=java.lang.Object@632cc9ed, public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)=java.lang.Object@632cc9ed, public abstract java.lang.Object org.springframework.data.repository.CrudRepository.findOne(java.io.Serializable)=java.lang.Object@632cc9ed}]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Feb 02, 2014 1:31:12 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
.......
SEVERE: The web application [/test] created a ThreadLocal with stop
INFO: The stop() method was called on component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/test]] after stop() had already been called. The second call will be ignored.
Feb 02, 2014 1:42:26 PM org.apache.catalina.startup.HostConfig undeploy
INFO: Undeploying context [/test]
此日志内容:曾经对数据库执行的任何查询(包括 findOne 和 findAll 等默认查询)都保存在内存中,无法卸载。
我已经阅读了一些解决方法 (like moving the mysql driver into the lib folder of tomcat ),但我不认为这是一个普遍问题,我认为这是由我的应用程序配置造成的。
这是我的配置:
Servlet 配置 web.xml
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>GPMM 2014 Feedback</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Spring Security -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/security.xml</param-value>
</context-param>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring Security -->
<!-- File upload -->
<filter>
<filter-name>multipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/admin/**</url-pattern>
</filter-mapping>
<!-- File upload -->
Spring mvc bean 配置:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<context:component-scan base-package="com.springapp.mvc.controller.admin"/>
<context:component-scan base-package="com.springapp.mvc.controller.user"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="2000000"/> <!-- File size in bytes. -->
</bean>
<!-- Data access management -->
<jpa:repositories base-package="data.repository"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="defaultPersistenceUnit"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- Data access maanagement -->
安全配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<http auto-config="true" authentication-manager-ref="adminauth">
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
<intercept-url pattern="/updatedb/**" access="ROLE_DBADMIN" />
<!--<intercept-url pattern="/game/**" access="ROLE_USER" />-->
<form-login login-page="/adminlogin" authentication-failure-url="/accessdenied" />
<logout logout-success-url="/admin" logout-url="/j_spring_security_logout" />
</http>
<authentication-manager id="adminauth">
<authentication-provider>
<password-encoder hash="sha-256"/>
<user-service>
<user name="admin" password="xxx" authorities="ROLE_ADMIN" />
<user name="dbadmin" password="xxx" authorities="ROLE_DBADMIN" />
<user name="user" password="xxx" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
和 JPA/Hibernate 配置:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>data.model.TestEntity</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/gpm" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.username" value="user" />
<property name="hibernate.connection.password" value="password" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
</properties>
</persistence-unit>
这是一个典型的代码示例:
@Controller
public class TestController
{
static final Logger logger = LogManager.getLogger(TestController.class);
@Autowired
private TestRepository testRepository;
@RequestMapping(value = "/admin/tests", method = RequestMethod.GET)
public String listTests(ModelMap model)
{
TestEntity gamegroup = new TestEntity();
model.addAttribute("test", test);
model.addAttribute("tests", testRepository.findAll());
return "admin/tests";
}
@RequestMapping(value = "/admin/tests/update", method = RequestMethod.POST)
public String updateTest(@ModelAttribute("test") TestEntity test, BindingResult result)
{
testRepository.save(test);
return "redirect:/admin/tests";
}
}
请指出我的配置或访问 mysql 的方式可能有什么问题。
【问题讨论】:
-
问题出在 MySQL 线程上。见here。
-
谢谢,我已经看过你的帖子,实际上已经实现了监听器,现在正在测试它,但是我有 4 个不同的泄漏(jdbc、事务、连接和一个我还不明白)。有时我觉得我上辈子得罪了神
-
看起来解决方案解决了jdbc和连接问题,不幸的是不是事务一:(
标签: hibernate tomcat spring-mvc jpa memory-leaks