I want to measure the percentage of memory used by HttpSession in a web application.
Is there any way to measure memory consumption with all HttpSessions in a running Tomcat instance at an arbitrary point in time without modifying the application?
What I have tried
- In Tomcat, the concrete class of
HttpSessionisorg.apache.catalina.session.StandardSession. I have profiled the application with VisualVM and specifiedorg.apache.catalina.session.StandardSessionin[Profiler]-[Memory settings]. But it shows only the size ofStandardSessionitself (the size ofConcurrentHashMapcontained inStandardSessionis not included). - I have profiled the application with Flight Recorder and viewed the result with Mission Control. But I cannot find out which objects are referenced from
HttpSession. - You can list all HttpSession with
org.apache.catalina.session.ManagerBase#findSessions()and measure the size ofHttpSessions with Byteman andSizeOf.deepSizeOf(). But this Byteman rule runs only when a newHttpSessionis created. I want measure memory consumption withHttpSessions at an arbitrary point in time (e.g. in every 30 seconds).
Advertisement
Answer
According to the comment from @LMC, I made a sample project to get the size of HttpSession with JMX: https://github.com/satob/SessionSize
Note that because you cannot access org.apache.catalina.session.ManagerBase directly, this project uses ByteMan. Store the ManagerBase object to a static field of the MBean SessionMonitor with Byteman like:
RULE Set ManagerBase object to MBean
CLASS ^org.apache.catalina.session.ManagerBase
METHOD initInternal
AT EXIT
IF TRUE
DO
traceln("SETTING SessionManager");
com.example.sessionsize.SessionMonitor.setSessionManager($this);
ENDRULE
and use it in the JMX interface like:
package com.example.sessionsize;
import org.apache.catalina.Manager;
import org.apache.catalina.Session;
import net.sourceforge.sizeof.SizeOf;
public class SessionMonitor implements SessionMonitorMBean {
private static Manager sessionManager = null;
public static void setSessionManager(Manager manager) {
sessionManager = manager;
}
@Override
public long getMemoryConsumption() {
if (sessionManager != null) {
try {
Session [] sessions = sessionManager.findSessions();
return SizeOf.deepSizeOf(sessions);
} catch(RuntimeException e) {
// Falied to get size of HttpSession object
e.printStackTrace();
return -2;
}
} else {
// SessionManager is not ready
return -1;
}
}
@Override
public long getNumberOfActiveHttpSession() {
return sessionManager.findSessions().length;
}
}
