[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
RE: [aspectj-users] Garbage collector behavior

Hi Matthew,

1. If the reaper only accesses a single object at a time, it could at worst
add a bit of contention, and never create deadlocks, right? One approach is
to create a reflective proxy for the BCEL bytecode without locking anything
and then swizzle the map entry at the last moment. This would absolutely
minimize contention.

There might value in using AspectJ to apply appropriate concurrency
strategies on a Java 1.3-, 1.4 and 1.5+ VM using best efforts, the
java.util.concurrent backport, and java.util.concurrent respectively. For a
1.3- VM, I'd just synchronize on the weaver for the update to the map. For
1.4+ I'd use a concurrent hash map (maybe extending it to concurrent weak
hash map).

This is an area where I plan to work on some reusable library aspects,
hopefully collaborating with Ramnivas who has written some nice examples.

I agree we need to analyze the memory usage carefully: intuitively the
memory used by aspects ought to be small, although in the Inspector case I'm
seeing an extra 2 MB per classloader which translates to 2 MB per JSP. If as
I believe this is caused by the redundant, sharable aspect bytecode, then it
is actually a pretty big problem that would affect many interesting aspects
that apply to a Web application. Re: using the aspect bytecode, doesn't the
new MAP provide sufficient reflective information to implement this kind of
proxy for aspects based on the bytecode definition? If not, do you know what
is still lacking?

2. I thought Alex said that weaver has to be reentrant. Either way, long
term it would be highly desirable to make it so and to just load aspects
(and everything) through the standard classloader mechanism instead of this
complex parallel bytecode loading mechanism that is really suited to
compilers and not load time environments, IMHO.

3. Re "I think weaving into well known ClassLoaders to allow a
ClassLoaderWeavingAdaptor that delegates to a parent would be natural too."
I am suggesting that we build on the technique you suggested, whereby we
write aspects that weave into common ClassLoaders like Tomcat's (especially
the JasperLoader for JSP) to add hooks after defining classes. My idea is
that we can encode knowledge of delegation into these aspects so we can set
up a proper hierarchical weaving structure based on knowledge of whether the
loaders are delegating or not. I think that having real hierarchy in the
weavers will allow another level of efficiency beyond what can be achieved
by sharing bytecodes. Of course if shared bytecodes

4. Re: "Sounds dangerous"
I would also say that if users explicitly configure a
delegating/nondelegating mode for a classloader hierarchy, they need to know
what they're doing. In truth Java users (developers) routinely have problems
with ClassLoader resolution already. But I would far rather have options
that are not a default that can be used to get acceptable performance in the
near term, if the benefit is compelling.

I don't think would be redundant in the general case, although if we
recognize all the popular non-delegating ClassLoaders it could be an obscure
option for custom ones (or maybe we publish a marker interface & an
From: aspectj-users-bounces@xxxxxxxxxxx
[mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Matthew Webster
Sent: Tuesday, November 01, 2005 9:23 AM
To: aspectj-users@xxxxxxxxxxx
Subject: RE: [aspectj-users] Garbage collector behavior


My only concern with a reaper thread would be the locking issues. I think
making the weaver re-entrant is a great goal but probably non-trivial. We
still need byte-code for aspects as we can't use Java reflection to obtain
cross-cutting meta-data and it's not a such big deal as the number of
aspects is small compared to the number of classes. However it may be
possible to create a hybrid that initially uses byte-code but after the
aspect is defined uses a Class object for Java meta-data. I don't think
there is any complexity in loading byte-code because it is encapsulated in
the BcelObjectType delegate and needed for binary weaving. 

>I think weaving into well known ClassLoaders to allow a
ClassLoaderWeavingAdaptor that delegates to a parent would be natural too. 
Please explain. 

>One thought: what if we allow a delegating flag in an aop.xml deployment
descriptor, which would indicate it is supporting normal delegation
semantics. This would let >us fairly easily reuse weaving data from a parent
classloader?s definitions? 
Sounds dangerous. Can't trust user configuration to get type resolution
correct. This may be redundant if we weave define class callbacks. 


Matthew Webster
AOSD Project
Java Technology Centre, MP146
IBM Hursley Park, Winchester,  SO21 2JN, England
Telephone: +44 196 2816139 (external) 246139 (internal) 
Email: Matthew Webster/UK/IBM @ IBMGB, matthew_webster@xxxxxxxxxx 
Please respond to aspectj-users@xxxxxxxxxxx 
Sent by:        aspectj-users-bounces@xxxxxxxxxxx 
To:        <aspectj-users@xxxxxxxxxxx> 
Subject:        RE: [aspectj-users] Garbage collector behavior 

I agree that only holding on to bytes that are actually woven would be a
useful optimization. 
I like your idea of weaving into popular ClassLoaders like Tomcat?s to avoid
using byte code for woven classes. Another technique that can work is to use
accessible object to invoke ClassLoader.findLoadedClass to determine if a
given class loader has loaded a class but won?t cause loading if it hasn?t.
I tested using this approach to create proxies instead of loading bytes, but
in this case the weaver has always defined the class in advance. This could
be done on a cache ?reaper? thread that periodically reclaims memory. 
To share memory among aspects, it would be useful if we could do the same
approach: rely on a proxy for the loaded .class representation of the
aspect, rather than keeping separate copies of the bytes in each
ClassLoader. What if we made the weaver set up reentrant, so that it just
loaded the aspects like any other class rather than having this separate
mechanism of loading bytecodes? It seems to me that the root of all the
complexity is separately loading and managing these bytecodes. This would
undoubtedly add complexity, since the weaver would be in an ?initializing?
mode while it is looping over aspect definitions. But the payoff would be
significant reuse. 
I think weaving into well known ClassLoaders to allow a
ClassLoaderWeavingAdaptor that delegates to a parent would be natural too. 
I think it?s really important to avoid 1-3 MB of overhead per ClassLoader
when there?s one ClassLoader per JSP. I also think this same need for
lightweight weaver extension support will be important when reconsidering
reweaving when there are build-time woven aspects that aren?t in the aop.xml
definition file? 


From: aspectj-users-bounces@xxxxxxxxxxx
[mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Matthew Webster
Sent: Monday, October 31, 2005 8:24 AM
To: aspectj-users@xxxxxxxxxxx
Subject: RE: [aspectj-users] Garbage collector behavior 


I suspect the 900 classes you see in world.delegate.loaded represent the
whole of your Spring application: this collection holds all types exposed to
the weaver. It can be trimmed using "<exclude within=..." but could be
changed to only hold classes that are actually woven. However if you weave
every class we need to retain a woven representation. I believe Adrian
introduced the expendableMap primarily to reduce the peak footprint of AJDT
during compile/weave. It allows types used purely for resolution to be
released. However the references between types are not weak so entries in
this map can be kept alive by types exposed to the weaver. This could be an
opportunity to reduce footprint at a GC. 

However there may be a way to reduce the permanent reliance on byte-code for
woven classes. Once a class has been successfully defined we could use
reflection. The trick is to safely get hold of the Class object. If we
control the class loader we could create a callback into the weaver enabling
it to replace its byte-code representation. This is not possible when using
the Java 5 agent. However in middleware environments such as Tomcat we could
weave the classloaders it creates to invoke the callback after a successful

As I have said before I don't think sharing information between weavers is
viable because the relationship between the class loaders with which they
are associated cannot be reliably determined e.g. web application loaders.
The best approach is to reduce the number of JavaClass BCEL objects we have
lying around by using reflection directly for bootstrap classes and latterly
for woven classes. There may also be more scope for weak references but
these involve indirection which can hurt performance. Longer term reliable,
transparent byte-code caching will also help enormously. It's something I
will be looking at as part of new Eclipse technology project:


Matthew Webster
AOSD Project
Java Technology Centre, MP146
IBM Hursley Park, Winchester,  SO21 2JN, England
Telephone: +44 196 2816139 (external) 246139 (internal) 
Email: Matthew Webster/UK/IBM @ IBMGB, matthew_webster@xxxxxxxxxx 
Please respond to aspectj-users@xxxxxxxxxxx 
Sent by:        aspectj-users-bounces@xxxxxxxxxxx 
To:        <aspectj-users@xxxxxxxxxxx> 
Subject:        RE: [aspectj-users] Garbage collector behavior 

I used a recent AspectJ dev to take more measurements on a development
version of my Glassbox Inspector (with a few more aspects than the alpha
one). It turns out the biggest problem I'm seeing is the overhead per
classloader, since Tomcat is creating one classloader per JSP using about
3MB each.

Here are the stats I'm seeing.

Memory use on startup (Tomcat 5.5 with 3 sample apps autostarted):
Without weaving: 22M
Weaving the inspector into all shared apps: 106M (after forcing GC)

The main memory user is the Spring 1.2.1 Web app (it has loaded over 900
classes). The other app loading over 100 classes is the Axis server Web app
(but less than 200).

At startup the loader for the Spring Web app has 67 type mungers, and over
800 loaded classes in world.delegate.loadedClasses, plus over 900
expendableMap entries (will they ever be evicted)?

It seems surprising that it would take about 80 MB to hold data about 1000
classes: does this really seem right/

I then walked through the ~15 pages of the Spring petclinic app.
Unfortunately, Tomcat loads *each JSP in its own ClassLoader*. So the memory
consumed went up yet again to 154M: about 3M per page (per class loader).

I am able to re-enable one helpful optimization that Matthew Webster and I
were testing: using reflective type delegates for bootstrap classes instead
of creating BCEL objects.

This takes my memory use down to 76M on startup (after forcing GC).
However, after hitting all the pages, it's again up to 127M (after forcing
GC). So the ~3M/classloader overhead is still about the same.

If I deploy a null aop.xml file in shared/lib (i.e., I define no aspects in
it), then the memory use on startup is 62M even with this optimization.
That's still 40M of overhead. After I visit most of the Petclinic pages the
memory use is up to 75M. So it appears there's about 1M of overhead per
classloader and my aspects are consuming 2M of overhead per classloader...

I think that weaving into Web apps is going to require some kind of scheme
to share information that mirrors classloading hierarchies.

I'd like to find more information about where the initial 45M of overhead
(200% of the total memory used without weaving) is going. I'd also like to
understand how the 3M/classloader overhead breaks down. My next step is to
use a memory profiler to get more data on each.

-----Original Message-----
From: aspectj-users-bounces@xxxxxxxxxxx
[mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Mathieu LEMAIRE
Sent: Friday, October 28, 2005 7:09 AM
To: aspectj-users@xxxxxxxxxxx
Subject: Re: [aspectj-users] Garbage collector behavior

Hi all,

I had to bench clearly memory consumptions and cpu usage overheads in 
those configs (aspect scalability, LTW / compile time W, no aspect at 
all) and here is what i got :

               weaving                  glM (KB)                  tgPk (KB)
                 ccM (KB)                  tgM
(KB)                  glT (ms)                  gcT (ms)
bench1                  CT few aspects                  70,085.41          
       97,510.18                  26.71                  65,470.21 
15,555.11                  4,590.33
CT many aspects                  70,064.73                  97,497.00      
           26.11                  65,470.54
LT few aspects
               117,904.67                  112,381.06                
 161.26                  112,381.06                  16,512.71
no aspects
               70,067.72                  97,515.85                  25.37  
               65,469.83                  15,737.30
LT many aspects
               119,323.28                  109,141.54                
 107.46                  109,141.54                  18,595.90
bench2                  CT few aspects                  77,874.13          
       72,646.21                  31.59                  72,646.21 
40,059.81                  6,447.67
CT many aspects                  75,584.27                  70,877.49      
           29.85                  70,877.49
LT few aspects
               103,814.15                  103,671.09                
 267.99                  93,940.62                  38,536.98
no aspects
               77,716.08                  72,481.75                  29.85  
               72,481.75                  40,638.22
LT many aspects
               102,670.77                  104,942.94                
 238.74                  95,081.41                  43,023.24

quick legend :

  * *glM : *globalMemoryConsumed
  * *tgPk : *peakMemoryConsumed
  * *ccM : *codeCacheMemoryConsumed
  * *tgM : *tenuredGenMemoryConsumed
  * *glT : *globalTime
  * *gcT : *gcTime

Those marks have been done using hotspot 1.5 and new JMX features..
Well those results should not stand as direct proofs but maybe just 
hints on the LTW consumption.

My aspects are really simple : for profiling I do not use any runtime 
check nor advanced aspectj features such as thisJointPoint** and when I 
say *many* aspects, i just mean 15, compared to *few* (1) :)

The important thing is that the overhead resides in the tenured gen 
pool, quite an old space.. that means that aspectj ltw still holds hard 
references somewhere and forcing collections should not help with any 
thing... Other interesting stuff is code cache consumption ; well I do 
not know much about that, but ltw needs much more than simply 
duplicating class defs.

The very good news is that compile time weaving do not introduce any 
distorsion ; that is great for my profiling !!

hope it helps.

aspectj-users mailing list

aspectj-users mailing list
aspectj-users mailing list