4 Replies Latest reply on May 4, 2010 3:57 PM by sean.tozer

    Profiling session memory usage in a Seam application

    alexandru.al.bologa.yahoo.com

      Hi,
      I'm currently working on a web application that uses JSF 1.2, Seam 2.1.2, Richfaces 3.3.0 and EJB 3.0 and is deployed on Jboss 4.2.2 GA server.


      I've been assigned the task of analyzing how much memory is used by a users session. By session I mean not only the Session Context of seam, but also the Conversation Context and whatever else might be stored on the server side in respect to one user/sessionid.
      I am using the TPTP profiler. The profiler works fine and I am able to analyze the memory usage of any given object instantiated during the Jboss run.


      Now for the question...
      Can anyone give me a hint on what exact objects I need to profile in order to have the full picture of what is stored on the session? Maybe there is a single object that holds the session map or something like this.


      I had an attempt which I don't consider successful:
      While running the web app, I requested an URL from the browser (thus creating the session). Next I went to the debug.seam page and looked at what was stored on the Session and Conversation Context. Next I profiled those exact classes and summed up their memory (totaled about 250 Bytes).
         I think this method is not exhaustive. For example, if I refresh the page several times, the total memory usage by the classes identified on the debug page doesn't increase. This is in contradiction with the fact that JSF saves extra View States for each request which are stored server side.

      I would be grateful if I could get some insiders on where to look, or maybe even a completely different approach to achieving my task.

        • 1. Re: Profiling session memory usage in a Seam application
          sbasinge
          This may make you a bit nervous, but I have a custom version of MarshalledValue.java which is part of JBoss.  I added to it's ToString, the size in bytes of the stored instance.  Then thru the JMX monitor you can see how many bytes each serialized object requires.  I simply compiled the java and created a jar file named a_myjbossaddon.jar and put into the <server>/lib directory.

          // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
          // Jad home page: http://www.kpdus.com/jad.html
          // Decompiler options: packimports(3)
          // Source File Name:   MarshalledValue.java

          package org.jboss.invocation;

          import java.io.*;
          import java.util.Arrays;

          // Referenced classes of package org.jboss.invocation:
          //            MarshalledValueOutputStream, MarshalledValueInputStream

          public class MarshalledValue
              implements Externalizable
          {

              public MarshalledValue()
              {
              }

              public MarshalledValue(Object obj)
                  throws IOException
              {
                  ByteArrayOutputStream baos = new ByteArrayOutputStream();
                  MarshalledValueOutputStream mvos = new MarshalledValueOutputStream(baos);
                  mvos.writeObject(obj);
                  mvos.flush();
                  serializedForm = baos.toByteArray();
                  mvos.close();
                  int hash = 0;
                  for(int i = 0; i < serializedForm.length; i++)
                      hash = 31 * hash + serializedForm[i];

                  hashCode = hash;
              }

              public Object get()
                  throws IOException, ClassNotFoundException
              {
                  if(serializedForm == null)
                  {
                      return null;
                  } else
                  {
                      ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm);
                      MarshalledValueInputStream mvis = new MarshalledValueInputStream(bais);
                      Object retValue = mvis.readObject();
                      mvis.close();
                      return retValue;
                  }
              }

              public byte[] toByteArray()
              {
                  return serializedForm;
              }

              public int size()
              {
                  int size = serializedForm == null ? 0 : serializedForm.length;
                  return size;
              }

              public int hashCode()
              {
                  return hashCode;
              }

              public boolean equals(Object obj)
              {
                  if(this == obj)
                      return true;
                  boolean equals = false;
                  if(obj instanceof MarshalledValue)
                  {
                      MarshalledValue mv = (MarshalledValue)obj;
                      if(serializedForm == mv.serializedForm)
                          equals = true;
                      else
                          equals = Arrays.equals(serializedForm, mv.serializedForm);
                  }
                  return equals;
              }

              public void readExternal(ObjectInput in)
                  throws IOException, ClassNotFoundException
              {
                  int length = in.readInt();
                  serializedForm = null;
                  if(length > 0)
                  {
                      serializedForm = new byte[length];
                      in.readFully(serializedForm);
                  }
                  hashCode = in.readInt();
              }

              public void writeExternal(ObjectOutput out)
                  throws IOException
              {
                  int length = serializedForm == null ? 0 : serializedForm.length;
                  out.writeInt(length);
                  if(length > 0)
                      out.write(serializedForm);
                  out.writeInt(hashCode);
              }

              private static final long serialVersionUID = 0xeacce0d1f44ad099L;
              private byte serializedForm[];
              private int hashCode;
             
              public String toString() {
                    return new ToStringBuilder(this).append("size", this.size()).toString();
                   
              }
          }
          • 2. Re: Profiling session memory usage in a Seam application
            yahawari

            have a look at



            SEAMHOME//examples//wiki//src//main//org//jboss//seam//wiki//admin//WikiHttpSessionManager.java





            it may help.

            • 3. Re: Profiling session memory usage in a Seam application
              alexandru.al.bologa.yahoo.com

              Thanks for the advice. I implemented the WikiHttpSessionManager in my own app. Added a little xhtml and now I can see the memory consumption per session.
              I think this is sufficient to get total session memory consumption. (hopefully Seam doesn't hide anything else outside the HTTPSession - for example a map on the application context that has as keys the session IDs... but believing this would make me a bit paranoid :) )


              I'm still considering the custom MarshalledValue implementation since it might yield some useful fine grained info about memory usage.


              • 4. Re: Profiling session memory usage in a Seam application
                sean.tozer

                This all sounds like something that could be valuable added to the Seam distribution as an option, to print out memory usage. I would imagine a number of people might be interested in something like that.