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
Ron,
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 define.
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:
http://www.eclipse.org/equinox/incubator/aspects/index.php.
Cheers
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
http://w3.hursley.ibm.com/~websterm/
Please respond to aspectj-users@xxxxxxxxxxx
Sent by: aspectj-users-bounces@xxxxxxxxxxx
To:
<aspectj-users@xxxxxxxxxxx>
cc:
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 :
benchmark
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
15,956.42
4,509.00
LT few aspects
117,904.67
112,381.06
161.26
112,381.06
16,512.71
2,179.00
no aspects
70,067.72
97,515.85
25.37
65,469.83
15,737.30
4,551.67
LT many aspects
119,323.28
109,141.54
107.46
109,141.54
18,595.90
2,380.67
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
41,238.57
6,379.33
LT few aspects
103,814.15
103,671.09
267.99
93,940.62
38,536.98
4,707.67
no aspects
77,716.08
72,481.75
29.85
72,481.75 40,638.22
6,409.00
LT many aspects
102,670.77
104,942.94
238.74
95,081.41
43,023.24
4,337.00
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.
--
Mathieu
_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-users
_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-users