Java webapp中可能存在内存泄漏-对垃圾收集和会话属性有疑问

Java webapp中可能存在内存泄漏-对垃圾收集和会话属性有疑问,java,memory-leaks,reference,garbage-collection,session-variables,Java,Memory Leaks,Reference,Garbage Collection,Session Variables,我一直在用VisualVM在我的pc上本地评测我的webapp。我很确定我有一个小的内存泄漏。在对应用程序进行快照之后,我选择了具有最多实例化对象的对象,并查看分配调用树,看看是否可以找到(我的)哪个类导致了“潜在泄漏” 我在树中找到了三个类,并查看了确定的方法 下面是我的一个servlet中的一段代码(一个方法)——该方法获取我希望保留在会话中的会话属性的名称,并删除其余属性 public void doPost(HttpServletRequest req, HttpServletRespo

我一直在用VisualVM在我的pc上本地评测我的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

//....
自评测我的webapp以来,到目前为止我所做的唯一修改是添加了将exemptAttributes[]对象数组设置为null

我的问题是—
如果将字符串数组(或任何对象)设置为会话属性,这是否意味着对该对象的引用(如果在代码中未设置为null)仍然是“引用的”并且不会被垃圾收集?

ExcemptAttributes引用的范围(而不是引用引用引用的实际对象)是方法中的try块。因此,您的问题的答案似乎是“否”


泄漏可能是因为您没有破坏会话吗?换句话说,如果您继续创建新会话并在这些会话中设置ExcemptAttributes对象,除非您正在清理旧的/未使用的会话,否则您的内存使用量将增加。(您可以在web.xml中设置会话超时)

要回答您的实际问题,不,取消该引用几乎没有任何作用。变量的作用域仅限于
try{}
块。一旦您离开try,它就会超出范围,并且该类不再持有任何引用。在“真实”的情况下,方法中的引用为空会对垃圾收集有用。它将一直保留,直到会话释放其引用为止

使用
ResultSet
Statement
的奇怪方式,或者干脆不清理旧会话,似乎更适合解决问题

如果将字符串数组(或任何对象)设置为会话属性,这是否意味着对该对象的引用(如果在代码中未设置为null)仍然是“引用的”,并且不会被垃圾收集

不完全是

如果已将对象设置为会话属性,则只要
会话
对象可访问,该对象将继续可访问(而不是垃圾收集)。
会话
对象很可能被servlet基础结构缓存在内存中很长一段时间

在这种情况下,将
null
赋值给局部变量没有任何用处。首先,不管怎么说,局部将超出范围,从GC的角度来看,这具有相同的效果。其次,您刚刚将对象引用复制到一个比局部变量有更长生存期的数据结构(会话)。。。因此,无论如何,该对象仍将是可访问的

简而言之,无论是否将
null
赋值给局部变量,对象都是可访问的

应对这种“泄漏”的可能方法包括:

  • 不要将对对象的引用放入会话属性中
  • 将会话属性设置为
    null
    ,或
  • 调整web容器的会话缓存策略,以便从缓存中删除空闲会话
  • 实施一个方案,在空闲一段时间后使会话失效(例如,注销用户)

感谢您的帖子。请您进一步阐述一下关于ResultSet和Statement对象的含义以及它们的使用方式……以及关于清理旧会话的含义。作为方法参数引入的ResultSet是什么?它是从哪里来的?为什么完全忽略它并覆盖引用?将要生成的语句是如何生成的?谁在关门?将处于未知状态的语句作为方法参数,并用它执行任意字符串SQL,然后让它挂起,这“看起来很奇怪”!ResultSet和Statement对象是在servlet的doPost方法中创建的。还创建了一个连接对象。每个对象在finally块(包含在doPost方法中)中闭合。ResultSet对象在创建时被初始化为null,并且在调用servlet的方法时被传入并由这些方法使用。我可以将这些特定的代码部分附加到我的代码片段中,这样您就可以自己查看了。这看起来很安全,但您似乎对java有一些误解。在java中,指针总是按值传递。将rs设置为方法内部的某个对象,不会导致doPost中的rs引用现在指向某个对象。它保持为空,并且将始终为空。它们是指向不同事物的独立参考。结束声明仍然应该结束它。感谢您进一步解释。大多数情况下,我使用ResultSet对象并将其传递给一个方法,然后该方法运行一个查询,然后,检索结果后,不再需要ResultSet对象。在方法内部的“rs”上调用close()方法会更有效吗?我很高兴知道这一点。正如我最初所想,方法中对象的范围是局部的,并且此后不再存在,对吗?关于,是的,在my web.xml中将其设置为20分钟。范围实际上是try{}块,甚至不是整个方法。包含声明的最里面的一对大括号定义了范围。关于你的4个建议(我感谢你),我认为我无法避免将对对象的引用放入会话属性中…选项#2-有大量会话att