2012-11-28 53 views
23

我正在Eclipse Juno中開發Java EE Web應用程序。我配置了Tomcat以使用JDBC連接池(org.apache.tomcat.jdbc.pool)和PostgreSQL數據庫。 下面是我的項目的META-INF/context.xml的配置: 當Tomcat中啓用了Context reload =「true」時,JDBC連接池的連接用完了

<?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中的屬性重新加載設置爲「真」自動如果檢測到變化重新加載web應用程序:

<Context reloadable="true">

我注意到,每次上述的自動重新加載是發生到PostgreSQL分貝10個更多的連接被保留(因爲在web應用程序的context.xml中INITIALSIZE =」 10" )。所以,10後改變PSQLException拋出:

org.postgresql.util.PSQLException: FATAL: sorry, too many clients already 
... 

如果我手動重新啓動Tomcat - 一切都很好,只是10個連接被保留。

是否有人知道解決此問題的方法,因此可以使用可重載設置開發「true」,並且不會在每次上下文重新加載時導致建立更多連接?

希望有任何幫助。

P.S.的Apache Tomcat版本7.0.32

+1

最有可能是http://stackoverflow.com/questions/8435359/why-do-connections-persist-when-i-undeploy-a-webapp-using-the-tomcat-7-jdbc-conn的副本 – Isaac

+1

@Isaac「它已從Tomcat 7.0.11更正」,但是我有7.0.32,結果仍然相同。所以基本上這是一個錯誤? – informatik01

+0

可能是迴歸。如果您確信自己正在釋放所有連接,並且問題仍然存在,那麼我會要求重新打開該錯誤報告。 – Isaac

回答

30

將該溶液(TL; DR)

爲了解決此問題,用值 「靠近」 到資源元素添加一個屬性closeMethod(記錄here)在context.xml文件中。

這是我的/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。


龍答案

OK,我發現上述溶液感謝到Apache Tomcat committor Konstantin Kolinko。我將this issue報告爲ASF Bugzilla上的Apache Tomcat錯誤,並且 原來它不是錯誤 (請參閱UPDATE 1)。

=== 更新1(2012年12月3日),又名 「新希望」 ===

那麼,它仍然被證明是一個錯誤Mark Thomas,是Apache Tomcat 7的發佈經理,confirmed那(報價):

「這是在JDBC池內存泄漏缺陷PoolCleaner實例 保留在連接池引用防止它被 GC'd 。
...
這個問題已經在trunk和7.0.x中修復,並將包含在 7.0.34之後。「

所以,如果你有一箇舊版本的Tomcat(小於7.0.34),使用上面的解決方案,否則, 開始的Apache Tomcat版本7.0.34,也應該像我描述了一個沒有問題。 (見UPDATE 2)

=== 更新2(2014年1月13日),又名 「問題反擊戰」 ===

好像在my bug report最初描述的問題仍然存在即使是目前最新的Apache Tomcat 7.0.50版本,我也使用Tomcat 7.0.47進行了複製(感謝Miklos Krivan指出了這一點)。儘管現在Tomcat有時會在重新加載後關閉更多連接,有時在重新加載之後連接數量會增加,然後保持穩定,但最終這種行爲仍然不可靠。

我仍然可以複製最初描述的問題(雖然也不是那麼容易:它可能與連續重新加載的頻率有關)。看起來這只是時間問題,即如果Tomcat在重新加載後有足夠的時間,它就會像應該那樣或多或少地管理連接池。正如馬克托馬斯在他的comment(引用)中提到的那樣:「根據closeMethod的文檔,這種方法的存在僅僅是爲了加速釋放GC所釋放的資源。」 (報價結束),看起來速度是決定性因素。

當使用由康斯坦丁Kolinko提出的解決方案(使用closeMethod =「接近」)一切工作得很好,並且保留的連接的數量是嚴格保持爲在context.xml文件定義。因此,似乎使用closeMethod =「close」是唯一真正的方法(目前),以避免在上下文重新加載後耗盡連接。

=== UPDATE 3(2014年1月13日)又名 「Tomcat的發佈管理器的返回」 ===

後面在更新2描述的行爲的奧祕就解決了。我收到馬克托馬斯(Tomcat發佈經理)的reply後,更多的細節已經被清除。我希望這是最新的更新。因此,錯誤確實固定作爲更新1.我在這裏張貼馬克的答覆中必不可少的一部分作爲報價(重點煤礦)提到:

的實際內存泄漏發現在調查此錯誤已按照註釋#4至#6的規定,在7.0.34以後已經固定爲 。

重新加載時未關閉連接的問題是 針對JNDI資源的J2EE規範的結果,因此此部分錯誤 報表無效。我正在修復此錯誤的狀態爲 ,以反映確實存在的內存泄漏已得到修復。

爲了說明爲何無法在 重新加載後立即關閉連接失敗,J2EE規範沒有提供任何機制來告知資源不再需要它。因此,容器可以做的所有 都清除對資源的引用,並等待 垃圾回收(這將觸發關閉池和關聯連接)。發生垃圾收集有時由JVM確定 所以這就是爲什麼它需要的時間的上下文重載作爲垃圾收集 可以不一段時間發生之後被關閉 連接不確定量。

Tomcat添加了Tomcat特有的JNDI屬性closeMethod,其中 可用於在停止 上下文時觸發顯式關閉JNDI資源。 如果等待GC清理資源不是 可接受,那麼只需使用此參數即可。 Tomcat默認不會使用這個 作爲,它可能會對 某些JNDI資源產生意想不到的副作用。

如果你想看到提供的告訴他們不再需要JNDI 資源的標準機制,那麼你需要遊說 J2EE專家小組。

結論

只需使用在這篇文章的開頭提出的解決方案(但是,爲了以防萬一,請記住,可以理論上使用它產生的JNDI相關的問題)。


替代解決方案

Michael Osipov用他CloseableResourceListener建議,以防止Web應用程序取消部署過程中由於左開資源的內存泄漏。所以你也可以試試看。


免責聲明
用於更新別名是由Star Wars膜系列的啓發。所有權利均屬於其各自所有者。

+1

不幸的是,Tomcat 7.0.35具有相同的問題,但closeMethod =「close」值解決了我的問題。 –

+1

Tomcat 7.0.47也有同樣的問題,但closeMethod =「close」完美無缺。 –

+0

@MiklosKrivan在UPDATE 3中查看關於此問題的最終描述。 – informatik01