Recently we have observed memory leakage in our production box. It turned out that it was WebLogic 8.1.4 that is leaking the session object. Some long expired sessions didn't get invalidated.
The story of how we would have suspected this in the first place would be too long to discuss it here. But here I'll present the code that we used to prove the WebLogic session leakage. The concept is simple, we used a session listener to track all the session with the help of the WeakReference. And a jsp page to display all the sessions.
The session listener first, add code below to WEB-INF/src/webpkg/SessionExplorerListener.java.
package webpkg;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.http.HttpSessionEvent;
public class SessionExplorerListener implements HttpSessionListener {
private static final Map sessionMap = new HashMap();
public void sessionCreated(HttpSessionEvent event) {
HttpSession session = event.getSession();
put(session.getId(), new WeakReference(session));
}
public void sessionDestroyed(HttpSessionEvent event) {
remove(event.getSession().getId());
}
public static synchronized Set getIds() {
return new HashSet(sessionMap.keySet());
}
public static synchronized HttpSession get(String id) {
WeakReference ref = (WeakReference)sessionMap.get(id);
return ref==null ? null : (HttpSession) ref.get();
}
private static synchronized void remove(String id) {
sessionMap.remove(id);
}
private static synchronized void put(String id, WeakReference ref) {
sessionMap.put(id, ref);
}
}
Then let's add our listener to web.xml:
<listener>
<listener-class>webpkg.SessionExplorerListener</listener-class>
</listener>
Finally, a jsp page that list all the active sessions, listSessions.jsp:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="ISO-8859-1"%>
<%@ page import="java.util.*, webpkg.SessionExplorerListener" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Session List</title>
</head>
<body>
<% Set sessionIdSet = SessionExplorerListener.getIds(); %>
Total Sessions: <%=sessionIdSet.size()%>
<table border="1">
<tr>
<th>Session ID</th>
<th>Create Time</th>
<th>Last Access</th>
<th>Timeout in (s)</th>
</tr>
<%
Iterator itr = sessionIdSet.iterator();
while(itr.hasNext()) {
String sessionId = (String)itr.next();
HttpSession ses = SessionExplorerListener.get(sessionId);
%>
<tr>
<td>
<% if (sessionId.equals(session.getId())) { %>
<b><%=sessionId%></b>
<% } else { %>
<%=sessionId%>
<% } %>
</td>
<td><%=new Date(ses.getCreationTime())%></td>
<td><%=new Date(ses.getLastAccessedTime()) %></td>
<td>
<%=ses.getMaxInactiveInterval()-(System.currentTimeMillis()
-ses.getLastAccessedTime())/1000 %>
/
<%=ses.getMaxInactiveInterval()%>
</td>
</tr>
<%
}
%>
</body>
</html>
This session leaking must have been there for long, we only found this out recently because we have released a new application that puts too much in user's session. Our memory usage is kept growing with those big sessions staying there forever. The problem is rather intermittent. Most of sessions do get cleaned up. We are still unclear of what caused the WebLogic to fail.