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 HttpSession
s 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
HttpSession
isorg.apache.catalina.session.StandardSession
. I have profiled the application with VisualVM and specifiedorg.apache.catalina.session.StandardSession
in[Profiler]-[Memory settings]
. But it shows only the size ofStandardSession
itself (the size ofConcurrentHashMap
contained inStandardSession
is 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 ofHttpSession
s with Byteman andSizeOf.deepSizeOf()
. But this Byteman rule runs only when a newHttpSession
is created. I want measure memory consumption withHttpSession
s at an arbitrary point in time (e.g. in every 30 seconds).
CodePudding user response:
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;
}
}