0

我一直在使用VisualVM在我的PC上本地分析我的web應用程序。我很確定我有一個小內存泄漏。在拍攝應用程序的快照後,我選擇了具有最多實例化對象的對象,並查看Allocation Call Tree以查看我是否能夠找到哪個類別(導致「潛在泄漏」)。可能在Java webapp中有內存泄漏 - 有關於垃圾回收和會話屬性的問題

我在樹中發現了三個我的類,並查看了精確定位的方法。

下面是我的一個servlet中的一段代碼(一種方法) - 此方法獲取我想保留在會話中的會話屬性的名稱,並刪除剩餘的部分。

public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { 

     Connection conn = null; 
     Statement stmt = null; 
     ResultSet rs = null; 


      try {   

      conn = ds.getConnection(); 
      stmt = conn.createStatement(); 

      HttpSession session = req.getSession(); 

      getExemptSessionAttributes(Customer_Number,rs,stmt,session);  

      }//try 

      catch (Exception e) { } 


      finally { 
        if (rs != null) { 
         try { rs.close(); } catch (SQLException e) { ; } 
        } 
        if (stmt != null) { 
         try { stmt.close(); } catch (SQLException e) { ; } 
        } 
        if (conn != null) { 
         try { conn.close(); } catch (SQLException e) { ; } 
        }   

      }//finally   

     }//post    


    public void getExemptSessionAttributes(int Customer_Number, ResultSet rs, Statement stmt,    HttpSession session) {  
     try { 
     rs = stmt.executeQuery("Select Name from exemptsessionattributes"); 
     String[] exemptAttributes = null; 
     int count = 0; 

     while(rs.next()) { 
      count++; 
      } 
     rs.beforeFirst(); 

     exemptAttributes = new String[count]; 
     count = 0; 

     while(rs.next()) { 
      exemptAttributes[count] = rs.getString(1); 
      count++; 
      } 
     session.setAttribute("ExemptSessionAttributes",exemptAttributes); 

     //garbage collect 
     exemptAttributes = null; 
       }//try 
       catch(Exception e) {} 
    }//end 

//.... 

迄今我已完成,因爲仿形我的web應用程序的唯一修改,是增加設置exemptAttributes []對象數組爲空的。

我的問題是 - 如果字符串數組(或任何物體)被設置成一個會話屬性,是否意味着該對象的參考,如果不在代碼設置爲空值,則仍然是「參考'並不會被垃圾收集?

回答

1

如果將String數組(或任何對象)設置爲會話屬性,是否表示對該對象的引用(如果未在代碼中設置爲null)仍然是「引用的」,並且不會被垃圾收集?

不完全是。

如果您已將對象設置爲會話屬性,那麼只要Session對象可到達,該對象就會繼續可到達(而不是垃圾回收)。很長時間以來,Session對象最有可能被servlet基礎結構緩存在內存中。

在這種情況下,將null分配給本地變量沒有任何用處。首先,本地即將超出範圍,從GC角度來看,這同樣有效。其次,您剛剛將對象引用複製到數據結構(Session對象)中,該對象的生命週期比局部變量長...因此該對象仍然可以繼續使用。

總之,無論您是否將null分配給本地變量,該對象都可以繼續到達而不管

打擊這一「泄密」的可能方式包括:

  • 不把對象的引用到會話屬性,
  • 設置會話屬性null,或
  • 調整Web容器的會話高速緩存策略,以便從高速緩存中刪除空閒會話。
  • 在空閒時間段之後實現對無效會話的方案(例如,將用戶註銷)。
1

exemptAttributes引用的範圍(不是引用引用的實際對象)是方法中的try塊。所以你的問題的答案似乎是「沒有」。

泄漏是否會因爲您沒有破壞會話?換句話說,如果您不斷創建新會話並在這些會話中設置exemptAttributes對象,那麼您的內存使用率將增加,除非您正在清理舊的/未使用的會話。 (您可以在web.xml中設置會話超時)

+0

我很高興知道這一點。正如我原先所想的那樣,方法中的對象範圍是局部的,之後就不復存在了,對吧?關於,是的,它在我的web.xml中設置爲20分鐘。 – katura 2011-01-25 22:48:10

+1

範圍實際上是try {}塊,甚至不是整個方法。包含聲明的最內層的一對大括號定義了範圍。 – Affe 2011-01-25 23:02:33

+0

+1影響。我的疏忽。 – 2011-01-25 23:15:23

0

要回答您的實際問題,請將該參考置零。該變量僅限於try {}區塊。只要你離開試驗,它就會超出範圍,而且這個類別不再有任何參考。有很少的'真正的'情況下,方法中的引用無效對垃圾回收有用。它會一直堅持到會議發佈其參考時爲止。

正在使用奇怪的方式ResultSetStatement,或者根本不清理舊會話,似乎是更好的候選人的問題。