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).
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; } }