我有 spring mvc 应用程序和 Tomcat 7.0.21 作为 servlet 容器。
当我尝试在应用程序中使用 jdbcTemplate 时,它无法正确重新部署 -
它阻止 jvm 清理 PermGen 内存。
错误代码的简单示例如下
(当然为了简单起见打破了 mvc 概念):
@Controller
class MainController {
private JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@RequestMapping("/")
public String mainPage() {
jdbcTemplate.queryForObject("SELECT val FROM tbl WHERE id=1",
String.class);
return "main";
}
}
没有jdbcTemplate.queryForObject(...)
它工作得很好,但是
当部署到 tomcat 时,它说:
Sep 21, 2011 1:54:38 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: The web application [/my] 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.
Sep 21, 2011 1:54:38 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/my] appears to have started a thread named [Timer-0] but has failed to stop it. This is very likely to create a memory leak.
此后,每次重新部署应用程序时,我都可以在 VisualVM 中看到 PermGen 的增长。
当然,我可以在每次需要时重新启动我的生产服务器
重新部署我的应用程序,但我想找出问题所在。
PS:数据源实现:
@Configuration
public class ApplicationConfig {
@Bean
DataSource dataSource(@Value("${jdbc.driver}") String driver,
@Value("${jdbc.url}") String url, @Value("${jdbc.user}") String user,
@Value("${jdbc.password}") String password) {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(user);
ds.setPassword(password);
return ds;
}
}
最佳答案
取消注册 JDBC 驱动程序应由数据源为您处理。请参阅this related question 。因此,请检查数据源实现的较新版本。 BasicDataSource
不是数据源的最佳选择。尝试使用 c3p0 并查看问题是否重现。
即使不是,Tomcat 也会为您清除它。顺便说一句,也要升级你的 tomcat - 它在最新版本中针对 DriverManager
泄漏进行了改进。
因此,PermGen 问题出在其他地方。这一直是 tomcat 的一个众所周知的问题,但他们声称这是泄漏的应用程序代码。这基本上是正确的,但很难追踪尚未注册的内容。 Tomcat 尝试清除 PermGen 问题的常见原因,但无法涵盖所有内容。
关于java - Spring jdbc模板内存泄漏在非常基本的应用程序中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7498063/