2014-03-03 17 views
6

我在jetty上使用jdbc連接池,在服務器實例上安裝了這種設置,一年內沒有問題。我已經切換到新的Ubuntu服務器,並保持內存不足。我剖析內存使用情況,並請參閱下面的頂級實例:如果未明確關閉,是否會導致ResultSet泄漏?

java.util.Hashtable$Entry (33%) 
com.mysql.jdbc.ConnectionPropertiesImpl$BooleanConnectionProperty (13%) 
com.mysql.jdbc.ConnectionPropertiesImpl$StringConnectionProperty (3%) 
com.mysql.jdbc.ConnectionPropertiesImpl$IntegerConnectionProperty (3%) 

我沒有明確的結束我的ResultSet情況下,我做的是這樣的:

Connection conn = null; 
PreparedStatement stmt = null; 
try { 
    conn = ...; 
    stmt = ...; 
    ResultSet rs = ...; 
    rs.useIt(); 
} 
finally { 
    if (stmt != null) { stmt.close(); } 
    if (conn != null) { conn.close(); } 
} 

的文檔說,語句在關閉時會關閉相關的ResultSet實例 - 這個ubuntu機器上的jdbc實現可能實際上沒有這樣做嗎?我沒有對我的代碼(打包的.war文件)進行任何更改,我只是將它原樣放入此ubuntu機器上的jetty實例中。

分析顯示那些com.mysql.jdbc.ConnectionPropertiesImpl實例不斷增長,所以猜測這可能是發生了什麼。

我只是想在我離開之前檢查並修改所有代碼以顯式關閉ResultSet實例。縱觀MySql Workbench,我沒有在客戶端連接視圖中看到任何不尋常的東西 - 我的應用程序連接進來了,好像清理好了。

謝謝

--------------------更新--------------------

我已經將ResultSet的所有實例都改爲立即關閉它們,以及finally {}塊中,就像我的Connection和PreparedStatement實例一樣。這似乎沒有幫助,但記憶力不斷增長。

周圍的一些更戳,我注意到類:

com.mysql.jdbc.JDBC4Connection 

和實例不會減少的數量。在大約10分鐘的正常運行時間後,我看到差不多5千次的實例(yike?)。

這個職位看起來很相似,我快到:

Memory leak in JDBC4Connection

的OP最後表示:

的ORM依賴於終結關閉連接到免費資源(有時會關閉結果集和語句),但池會將連接保持打開幾個小時,如果出現任何高峯,則會導致OOM。

我不明白這意味着什麼,或者如何解決這個問題。我很確定我現在到處關閉我的資源(否則,當我在其他Windows服務器上運行同一個Web應用程序時,我可能也在那裏看到了泄漏?)。

--------------------更新--------------------

Still看到相同的行爲,這就是我準備開在我處理的每個請求的數據庫連接(檢查省略錯誤):

public class DsHelper { 
    private static DsHelper sInstance; 
    private DataSource mDs; 

    public DsHelper() { 
     InitialContext ctx = new InitialContext(); 
     mDs = (DataSource)ctx.lookup("java:comp/env/jdbc/myds"); 
    } 

    public static DsHelper get() { 
     if (sInstance == null) { 
      sInstance = new DsHelper(); 
     } 

     return mInstance; 
    } 

    public DataSource getDataSource() { 
     return mDs; 
    } 
} 

使用它:

protected void doGet(HttpServletRequest request, 
        HttpServletResponse response) 
{ 
    Connection conn = null; 
    try { 
     conn = DsHelper.get().getDataSource(); 
     ... 
    } 
    finally { 
     if (conn != null) { conn.close(); } 
    } 
} 
+0

關閉ResultSet也是一種很好的做法,但我認爲關閉Statement語句也會使ResultSet失效(我懷疑關閉)。我不相信這是保證,但這就是爲什麼你應該[清理自己](http://www.frischcode.com/2013/11/clean-up-after-yourself.html)。 –

+0

我認爲他們都是封閉的,仍然看到MEM增長 - 儘管我更新了一些新的信息,謝謝! – user3203425

+0

你是如何打開連接的?你使用DriverManager還是某種DataSource(哪個?)? –

回答

2

ResultSet的泄漏是出了名普遍。明確地關閉它們是一個非常好的主意,並且值得每一點努力去做的事情。去這樣做!認真。

不同的虛擬機實現處理垃圾收集的方式不同。這可能是爲什麼你看到東西堆積在你的新環境中。

在Oracle上,ResultSet對象是稀缺服務器資源(遊標)的反映,如果不明確關閉它們,最終服務器用完,其他連接的工作開始失敗。

去幹淨他們!

+0

好吧,我認爲他們現在都明確關閉,但仍然看到相同的行爲。更新了我原來的帖子並附上了一些更新信息,謝謝 – user3203425

1

基於語句javadoc,ResultSet不需要顯式關閉。

From javadocs page

注:當一個Statement對象關閉,其當前的ResultSet對象, 如果存在的話,也被關閉。

但是我會建議一旦任務完成就關閉ResultSet。 Oracle的Statement實現,即使在關閉連接之後也存在打開遊標的問題。因此,可能會出現「超出最大打開遊標數」等異常情況。

您可以避免顯式關閉Statement以及java 1.7中引入的最新功能。 更好&更乾淨的代碼是(如果你使用的是Java 1.7+)

public static void viewTable(Connection con) throws SQLException { 

    String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES"; 

    try (Statement stmt = con.createStatement()) { 
     ResultSet rs = stmt.executeQuery(query); 

     while (rs.next()) { 
      String coffeeName = rs.getString("COF_NAME"); 
      int supplierID = rs.getInt("SUP_ID"); 
      float price = rs.getFloat("PRICE"); 
      int sales = rs.getInt("SALES"); 
      int total = rs.getInt("TOTAL"); 

      System.out.println(coffeeName + ", " + supplierID + ", " + 
           price + ", " + sales + ", " + total); 
     } 
    } catch (SQLException e) { 
     JDBCTutorialUtilities.printSQLException(e); 
    } 
} 

遵守try塊語法的差異,觀察有沒有明確的關閉方法調用。它在內部得到照顧。參考 - try-with-resources Statement

+0

由特定的JDBC驅動程序實現來正確關閉資源。 API文檔並不一定意味着所有的實現都符合! –

+0

@MarkRotteveel但他們肯定他們呢?當然,他們必須通過認證步驟? – EJP

+0

@EJP號。另請參閱DB2的批處理實現。提示,它不像其他人的。 –

相關問題