我正在Eclipse Juno中开发JavaEEWeb应用程序。我已将Tomcat配置为与PostgreSQL数据库一起使用JDBC连接池(org.apache.tomcat.jdbc.pool)。这是我的项目的META-INF / context.xml中的配置:
<?xml version="1.0" encoding="UTF-8"?> <Context> <!-- Configuration for the Tomcat JDBC Connection Pool --> <Resource name="jdbc/someDB" type="javax.sql.DataSource" auth="Container" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://localhost:5432/somedb" username="postgres" password="12345" maxActive="100" minIdle="10" initialSize="10" validationQuery="SELECT 1" validationInterval="30000" removeAbandoned="true" removeAbandonedTimeout="60" abandonWhenPercentageFull="50" /> </Context>
我的应用程序是使用Eclipse部署到Tomcat的,并且在Tomcat的context.xml中,可重载属性设置为“ true”,以便在检测到更改时自动重载该Web应用程序:
<Context reloadable="true">
我注意到,每次发生上述自动重装时,都会保留10个到PostgreSQL db的连接(因为在webapp的context.xml initialSize=“10”中)。因此,在进行10次更改后,将引发PSQLException:
org.postgresql.util.PSQLException: FATAL: sorry, too many clients already ...
如果我手动重启Tomcat-一切正常,并且仅保留10个连接。
有谁知道解决此问题的方法,因此可以将reloadable设置为“ true”进行开发,而不会在每次重新加载上下文时导致池化更多的连接吗?
将不胜感激。
PS Apache Tomcat版本7.0.32
为了解决此问题,请在context.xml文件中的 Resource 元素中添加一个值为“ close ” 的属性closeMethod(在此处记录)。
closeMethod
这是我的/META-INF/context.xml文件的正确内容:
<Context> <!-- Configuration for the Tomcat JDBC Connection Pool --> <Resource name="jdbc/someDB" type="javax.sql.DataSource" auth="Container" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://localhost:5432/somedb" username="postgres" password="12345" maxActive="100" minIdle="10" initialSize="10" validationQuery="SELECT 1" validationInterval="30000" removeAbandoned="true" removeAbandonedTimeout="60" abandonWhenPercentageFull="50" closeMethod="close" /> </Context>
注意属性 closeMethod 。我对其进行了测试,现在连接的数量严格按照 context.xml 文件中的定义保持!
注意可能 有一个时刻(与JNDI相关)。有关完整说明,请参见UPDATE 3。
好的,感谢Apache Tomcat提交者KonstantinKolinko,我找到了上述解决方案。我将此问题报告为ASF Bugzilla上的Apache Tomcat错误, 事实证明这不是错误 (请参阅UPDATE 1)。
=== 更新1(2012-12-03)又名“新希望” ===
好吧,事实证明那仍然是一个 错误 。Apache Tomcat 7版本管理器Mark Thomas 确认(引用):
“这是jdbc-pool中的内存泄漏错误。PoolCleaner实例保留了对ConnectionPool的引用,从而防止了它被GC损坏 。… 这已在trunk和7.0.x中修复,并将在7.0.34及以后版本中包含。 。”
因此,如果您拥有较旧的Tomcat版本(低于7.0.34),请使用上述解决方案,否则, 从Apache Tomcat 7.0.34版开始,应该不会出现我所描述的问题。 (请参阅更新2)
=== 更新2(2014-01-13)又名“问题反击” ===
即使对于当前最新的Apache Tomcat 7.0.50版,似乎仍然存在我的错误报告中最初描述的问题,并且我还使用Tomcat 7.0.47复制了该问题)。尽管现在Tomcat有时会在重新加载后设法关闭其他连接,有时在一次重新加载后会增加连接数量,然后保持稳定,但是最终这种行为仍然不可靠。
我仍然可以重现 最初描述的问题(尽管同样不那么容易:它可能与连续重新加载的频率有关)。似乎只是时间问题,即,如果Tomcat在重新加载后有足够的时间,它将或多或少地管理连接池。正如马克·托马斯(Mark Thomas)在他的评论(引号)中所提到的:“根据closeMethod的文档,该方法仅用于加快资源的释放,而这些资源本来可以由GC释放的。” (报价结尾),速度似乎是决定性因素。
使用Konstantin Kolinko提出的解决方案(使用closeMethod=“close”)时,所有工作都很好,并且保留的连接数严格按照context.xml文件中的定义进行。因此看来,使用closeMethod =“close”是目前唯一避免在重新加载上下文后用尽连接的正确方法。
=== 更新3(2014-01-13)又名“返回Tomcat版本管理器” ===
解决了UPDATE 2中描述的行为背后的谜团。在收到Mark Thomas(Tomcat版本管理器)的答复后,现在已经清除了更多详细信息。我希望这是最后更新。因此,该错误 的确得到了修复, 如UPDATE 1所述。我在此处将Mark的答复的重要部分作为引号(强调我的)发布:
调查此错误时发现的实际内存泄漏已在7.0.34及更高版本中按注释4至6修复。 连接问题在重新加载时未关闭是JNEE资源的J2EE规范的结果,因此,错误报告的此部分无效。我正在修复此错误的状态,以反映确实存在的内存泄漏已得到修复。 为了进一步说明为什么重新加载后立即关闭连接失败的原因无效,J2EE规范没有为容器提供任何机制来告诉容器不再需要该资源。因此,容器所能做的就是清除对资源的引用并等待垃圾回收(这将触发池和关联连接的关闭)。垃圾回收是在JVM确定的时间发生的,因此 这就是在上下文重载后关闭连接花费不确定的时间的原因, 因为一段时间内可能不会发生垃圾回收。 Tomcat已添加了特定于Tomcat的Tomcat JNDI属性closeMethod,该属性可用于在上下文停止时触发JNDI资源的显式关闭。 如果等待GC清理资源是不可接受的,则只需使用此参数 。Tomcat默认情况下不使用此功能,因为 它可能会对某些JNDI资源产生意料之外的副作用 。 如果您希望看到提供了一种标准机制来告知JNDI资源不再需要它们,那么您需要游说J2EE专家组。
调查此错误时发现的实际内存泄漏已在7.0.34及更高版本中按注释4至6修复。
连接问题在重新加载时未关闭是JNEE资源的J2EE规范的结果,因此,错误报告的此部分无效。我正在修复此错误的状态,以反映确实存在的内存泄漏已得到修复。
为了进一步说明为什么重新加载后立即关闭连接失败的原因无效,J2EE规范没有为容器提供任何机制来告诉容器不再需要该资源。因此,容器所能做的就是清除对资源的引用并等待垃圾回收(这将触发池和关联连接的关闭)。垃圾回收是在JVM确定的时间发生的,因此 这就是在上下文重载后关闭连接花费不确定的时间的原因, 因为一段时间内可能不会发生垃圾回收。
Tomcat已添加了特定于Tomcat的Tomcat JNDI属性closeMethod,该属性可用于在上下文停止时触发JNDI资源的显式关闭。 如果等待GC清理资源是不可接受的,则只需使用此参数 。Tomcat默认情况下不使用此功能,因为 它可能会对某些JNDI资源产生意料之外的副作用 。
如果您希望看到提供了一种标准机制来告知JNDI资源不再需要它们,那么您需要游说J2EE专家组。
只需使用本文开头提供的解决方案即可(但以防万一,请记住,从 理论上讲 ,使用它可能引起与JNDI相关的问题)。
MichaelOsipov建议使用他的_CloseableResourceListener_](http://mo-tomcat-ext.sourceforge.net/user-guide.html#CloseableResourceListener) ,它可以防止在取消部署Web应用程序期间由于打开的资源导致的内存泄漏。因此,您也可以尝试一下。
免责声明 UPDATES的别名来自《星球大战》电影系列。所有权利均属于其各自所有者。