Java webapp中可能存在内存泄漏-对垃圾收集和会话属性有疑问
我一直在用VisualVM在我的pc上本地评测我的webapp。我很确定我有一个小的内存泄漏。在对应用程序进行快照之后,我选择了具有最多实例化对象的对象,并查看分配调用树,看看是否可以找到(我的)哪个类导致了“潜在泄漏” 我在树中找到了三个类,并查看了确定的方法 下面是我的一个servlet中的一段代码(一个方法)——该方法获取我希望保留在会话中的会话属性的名称,并删除其余属性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
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容器的会话缓存策略,以便从缓存中删除空闲会话
- 实施一个方案,在空闲一段时间后使会话失效(例如,注销用户)