4 Replies Latest reply on Aug 18, 2008 1:27 PM by Andrew Rubinger

    Unnecessary memory allocation in MethodMetaData & MethodHash

    Lucas ----------- Newbie

      Hi,

      Last time I noticed that our application that we are working on is used to allocating around 500MB per second. As it can be expected GC is getting crazy ;)
      To accomplish one request our application perform around 10-20 remote invocations.
      Load under which application allocate 500M/s is about 100 request per second.

      I just finished small test. The goal of test was check how much memory is allocated per EJB invocation and find a way to optimize it.
      So testing environment was prepared:
      Client ---> FacadeBean ----> Worker MDB ------ (X times) -----> TargetBean

      So Client connect to Facade which was entry point. Facade put one message describing testcase into queue (home many invocation, local or remote interface should be used). Worker MDB perform testcase by invoking TargetBean in loop.

      Testcase:
      500 000 invocations to TargetBean was performed. Each invocation use null values as parameters to reduce synchronization.

      I found out that one of hot spots of memory allocation was method:
      java.lang.reflect.Method.toString()
      which was mostly invoked by following two classes:
      org.jboss.aop.metadata.MethodMetaData.getMethodMetaData(java.lang.reflect.Method, Object, Object)
      org.jboss.aop.util.MethodHashing.calculateHash(java.lang.reflect.Method)

      So I introduced small cache for these strings and modified above two classes to use this cache.

      Results:

      
      Remote interface:
       time[ms] allocatedMemory[GB] GCscavenge
      Baseline: 49559 37.67 7878
      Optimized: 36910 23.38 5339
      
      Local interface:
       time[ms] allocatedMemory[GB] GCscavenge
      Baseline: 18705 18.04 3856
      Optimized: 5267 1.41 449
      


      Time - is the time needed to accomplish all invocations
      allocatedMemory - is amount of memory that was allocated to accomplish all invocation. It is not exactly value, it should be treated as estimation, it was measured by -Xloggc
      GCscavenge - number of scavenge GC events, measured by -Xloggc

      Do you think it can be point for optimization?
      3 times faster for local invocations and ~25% faster for remote.
      Of course my implementation was extremely simple:
      1) concurrent access wasn't taken under consideration - ConcurrentHashMap was used but only one thread thread were used in test scenario so
      2) cache maintenance wasn't taken under consideration - is it can cause memory leak if applications will be redeployed often ?

      Let me know if you want more details about results.

      BR

      ps. notice that performance improvement depends on method signature ... so ... to achieve better performance we should use shorter package names ;)