recently someone had a strange problem with Groovy, a VM specific one.
He got OutOfMemoryErrors because his classes where not garbage collected
in the IBM VM, even though they were in Sun VM. We found out how to
solve the problem, but it seems specification did let room here for how
to collect classes if they are indirectly soft referenced.
Another problem Groovy is facing atm is, that it uses a lot of
SoftReferences for caches, meaning memory will be consumed big time. The
funny thing is, that we wouldn't even need SoftReferences for these
caches, but there is simply no other possible way... unless you guys
here tell me a different story.
Basically we have caches that map classes to helper structures, like our
meta class for example. The meta class is needed for almost any action
on the class, so we cache the class. We tried to use WeakReferences, but
that resulted in the meta class to be collected quite early, and since
the creation is expensive it proofed to be very bad the performance -
especially on low memory.
If we keep that structure, then we would really need a different kind of
reference... One that allows us to make a hard reference from the class
object to our meta class. Something like:
reference = new LinkingReference(x,y)
cache management would then work with the reference, x and y would be
PhantomReferenced by the LinkingReference, but there would be a VM
generated hard link between x and y. No ReferenceQueue would be needed
for the hard reference, only for the references of the LinkingReference
to x and y. that would make live so much more easy for us... basically
we would need that for arbitrary objects, not only classes. If we had
that Groovy could run with a much lower memory profile and most of our
memory management structures (which are concurrent) could be removed.
Of course I am no VM expert, and maybe John can comment on this, but the
hard reference management itself should be in the VM already, so what is
missing is to add a hard reference to an existing object... which may
invalidate some internal structures...
I am also interested in knowing if such a reference would be of interest
for other language implementations as well.
bye Jochen
--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
~~ Robert.
--
~~ Robert Fischer.
Grails Training http://GroovyMag.com/training
Smokejumper Consulting http://SmokejumperIT.com
Enfranchised Mind Blog http://EnfranchisedMind.com/blog
Check out my book, "Grails Persistence with GORM and GSQL"!
http://www.smokejumperit.com/redirect.html
Attila.
There's a rather heated discussion about this going on over on
core-libs-dev, MarkMail link
http://markmail.org/thread/zw2hrkho4ro5fykp
Patrick
I think it very much depends on the implementation how much it can
actually solve. Like my reference idea you have to keep some kind of
handler. If not, then one key might be used by multiple parts... which
would be bad.
I would say that my LinkedReference can simulate ClassLocal, only that
my solution is not for classes alone. But even if it were for classes
alone it would remove a big part of smelly code from Groovy.
ah, interesting... there is much talk about ephemerons.. my idea seems
to be a variant of this... or exactly this
Is there any material about plans to add ephemerons to the JDK? Using
google I wasn't able to ind anything. Only that thread is takling about
it seems.
> Is there any material about plans to add ephemerons to the JDK? Using
> google I wasn't able to ind anything. Only that thread is takling about
> it seems.
It seems to me that it should be possible to simulate ephemerons today
using phantom refs. The ephemeron is created with a key and a value,
and holds a strong reference to the value. It creates a reference
queue and requests a phantom reference to the key -- we subclass
PhantomReference so that we can recover the ephemeron.
A low-priority thread polls the queue; when a key has been GC'd, the
ephemeron is informed, gets a weak reference to the held value, drops
the strong value, and hangs on to the weak ref.
Does that seem feasible?
--
GMail doesn't have rotating .sigs, but you can see mine at
http://www.ccil.org/~cowan/signatures
As with many things in JRuby, I hacked this exact use case using
reflection on a Sun JDK. Basically I did the following:
1. Create a "TypeHolder" annotation
2. Create a "TypeHolderImpl" class that acts as a reference holder
3. Make "TypeHolderImpl" implement the "TypeHolder" annotation interface
(requires code generation, obviously)
3. Using reflection, forcibly insert a "TypeHolderImpl" instance into
the java.lang.Class annotation table
Once you've done this, you can access the "attached" data by simply
requesting the TypeHolder.class annotation from the Class object and
casting it back to TypeHolderImpl.
Hacky, sure. But it worked. I'm not using it for anything at present.
- Charlie
that's not enough for us. We have even a SoftReference to the value,
still we get problems, because for SoftReferenced Class instances the
spec seems not to say that these classes have to be collected before a
OutOfMemoryError occurs.
We also had a problem with the low priority thread. For one it is
possible that the thread won't remove the value fast enough once the
memory is low.. and as a second possibility we had Groovy running on
Glassfish and Groovy was used as library on a per web application basis.
But since the thread was running the Groovy runtime couldn't be
unloaded. Originally we added the thread because it seemed to be
faster... I then removed the thread and removed it with a queue check
when ever a reference is added, which is just as fast.
But both solutions are not ideal considering the way the GC seems to work
but this works only for classes that you can change. If it is a class
coming from some parent loader, that you have no control over, then it
won't work.. or do I see that wrong?
Maybe the typical usage scenario is different here with Groovy
No, this works for all classes, but you have to subvert reflection and
have appropriate security allowances. I'm actually modifying state
inside the java.lang.Class objects themselves.
Like I said, it's a hack, but it saves you associating state with Class
objects in an external structure. If the java.lang.Class object goes
away, so does your data.
- Charlie
It's the closest thing I know of to a systematic overview of these
sorts of RFEs. (Caveat: I'm not a GC expert.)
On Mar 10, 2009, at 5:21 AM, Jochen Theodorou wrote:
> If we keep that structure, then we would really need a different
> kind of
> reference... One that allows us to make a hard reference from the
> class
> object to our meta class. Something like:
>
> reference = new LinkingReference(x,y)
Making this work in a GC is probably hard. GCs are designed to work
locally on compact representations of the heap graph. Adding a link
"on the side" like this seems to require non-local operations in inner
loops that have been carefully designed to exploit locality (e.g., in
L1/L2 caches). I'm not saying it's impossible, but it needs to be a
big enough win to pay for a considerable engineering effort.
As I see it, the difference between this and weaker proposals is that
it (in effect) injects a field into an object, without the object's
cooperation. If we're going to ask the GC to inject reference values
into objects, let's go the whole way and inject module-specific
annotations (internally, fields) into uncooperative objects. It's
very hard to do this, especially in a non-relocating GC, without
bloating the header of every object, whether the feature is used or not.
The weaker link injection scenarios can be done with cooperative
objects that have APIs to acept: Thread, Class, ClassLoader, etc.
A variation on this design is to use interface injection. One of its
use cases is putting class-local values on uncooperative classes.
E.g., putting a GroovyMetaClass on java.lang.String. (We talked about
this last JavaOne.) Again, this is more feasible because it only
applies to classes, not arbitrary objects.
-- John
Yes, that goes in the direction... this link method could even be void
as far as I am concerned.
> On Mar 10, 2009, at 5:21 AM, Jochen Theodorou wrote:
>
>> If we keep that structure, then we would really need a different
>> kind of
>> reference... One that allows us to make a hard reference from the
>> class
>> object to our meta class. Something like:
>>
>> reference = new LinkingReference(x,y)
>
> Making this work in a GC is probably hard. GCs are designed to work
> locally on compact representations of the heap graph. Adding a link
> "on the side" like this seems to require non-local operations in inner
> loops that have been carefully designed to exploit locality (e.g., in
> L1/L2 caches). I'm not saying it's impossible, but it needs to be a
> big enough win to pay for a considerable engineering effort.
>
> As I see it, the difference between this and weaker proposals is that
> it (in effect) injects a field into an object, without the object's
> cooperation.
it could work as if we had a field without a name on x and the field
value would be y, yes...
> If we're going to ask the GC to inject reference values
> into objects, let's go the whole way and inject module-specific
> annotations (internally, fields) into uncooperative objects. It's
> very hard to do this, especially in a non-relocating GC, without
> bloating the header of every object, whether the feature is used or not.
I see... unless there is already a slot for this and some kind of array
or list structure to keep the references? Wouldn't that be possible? I
am not really talking about injecting the field then. I am thinking of
letting every objects have that slot from the beginning.. maybe it would
be part of the header? The bloating should be limited then I think.
> The weaker link injection scenarios can be done with cooperative
> objects that have APIs to acept: Thread, Class, ClassLoader, etc.
>
> A variation on this design is to use interface injection. One of its
> use cases is putting class-local values on uncooperative classes.
> E.g., putting a GroovyMetaClass on java.lang.String. (We talked about
> this last JavaOne.) Again, this is more feasible because it only
> applies to classes, not arbitrary objects.
well, if it works for classes then it would solve 100% of the problems
of this kind in Groovy 1.5.x, but in not for per instance MetaClasses,
as we have them since 1.6.
You know, when I first heard of instrumenting java classes I thought
what a great opportunity this could be. But the actual restrictions they
have made them nearly unusable for many cases. In Groovy it is a common
thing to have an arbitrary object from a parent loader we don't control.
Anything that would help us would have to work with such an object or
at last on its class
Now in case of my reference idea the actual realization of the hard link
would be fully up to the VM, since we wouldn't need any access to the
link itself. Only maybe to cut that link, but that is out of scope for
Groovy and could be simulated if not provided. This also means the link
is fully hidden from the programmer.
As for interface injection... I am worried about for example:
"""
If a type check ever finds that a given class does not implement an
interface, that interface cannot later be injected into the class.
"""
What if an object comes from Java land into Groovy land and such a check
has happened already? What ever we use to inject the interface cannot
happen before the object enters Groovy land... how ever the injection is
done itself. I didn't look at the prototype, but if interface injection
again requires special action at the class loader level, then it might
not be usefull to us at all... Also I wonder what happens if the class
provides a method that also exists in the interface. I assume we cannot
inject that method then... which means we would have to resort to clunky
method names that hopefully are never used by the user.. or am I wrong
here? or worse... what if for example the return types conflict?
But considering all these problems are actually no problems, then there
is still the fact that if I cast the object to this interface then it
will show all that internal information. You wrote in your blog for
example about GroovyObject and considering Attila's work with a
generalized MOP this effect is in fact what we want. But it feels like
making a field public that should be private instead.
oh? I guess I should reread your post carefully to see why it is
possible for for example java.lang.String...
you wrote:
> 1. Create a "TypeHolder" annotation
> 2. Create a "TypeHolderImpl" class that acts as a reference holder
> 3. Make "TypeHolderImpl" implement the "TypeHolder" annotation interface
> (requires code generation, obviously)
> 3. Using reflection, forcibly insert a "TypeHolderImpl" instance into
> the java.lang.Class annotation table
Creating an annotation is sure no problem. And TypeholderImpl... I
didn't grasp that the VM allows you to implement an annotation
interface... interesting. But ok...
The third step is unclear to me. How do I forcibly insert my
implementation into the Class annotation table? I would assume you mean
getAnnotations() and then change the returned array... no, that cannot
be it... so what is the trick?
> Like I said, it's a hack, but it saves you associating state with Class
> objects in an external structure. If the java.lang.Class object goes
> away, so does your data.
well, we have to hack all the time to go around limitations of the VM,
don't we ;)
Here's the actual code in OpenJDK's java.lang.Class:
// Annotations cache
private transient Map<Class, Annotation> annotations;
private transient Map<Class, Annotation> declaredAnnotations;
I just insert my fake annotation there :)
- Charlie
ah, ok... so it most probably will not work with another VM?
There are other VMs? :)
Seriously though...most of the JVMs out there license Sun's
implementation of the core classes, so I suspect this would work on a
lot of them. And the others...well, we could have a separate hack for
them, if people really need it.
- Charlie
Also, FWIW, the reason we're not using this in JRuby to track Java-class
metadata is because it obviously depends on security settings being lax
enough to setAccessible the annotation collections. I'm not sure it
would be a good general solution, but it could be used when possible
with a fallback to existing caching mechanisms.
It also has the down side that whatever you insert in a given class darn
well better work across that class across all child classloaders. So for
classes loaded at the highest levels, you'd still need some indirection
to get the appropriate metadata for the "current" Groovy or JRuby
runtime. It could also be an issue for interface injection, though in
both cases it may be mitigated by having a separate TypeHolder loaded at
the lower-level; there would then be multiple entries in the map, and
the problem is solved. Now you just need to make sure they're cleaned up
if the child classloader goes away :)
- Charlie
> What if an object comes from Java land into Groovy land and such a
> check
> has happened already?
The injected interface would be defined and controlled by Groovy and
probably should be package-private.
Even if it were public, so that random code could grab it and say "foo
instanceof GroovyInject", the first time it happens for foo's class
Foo, Groovy would be asked to fill in the GroovyInject methods on
Foo. Basically, that would be Foo's entry into Groovy-land.
(If for some reason this is too early, and it is a violation of some
usage rule, then Groovy could defer the question by throwing an error
of some sort; that would of course terminate the instanceof bytecode
abnormally.)
After GroovyInject is injected, its getGroovyMeta method would
(presumably) return a constant customized Groovy metaclass tailored to
Foo.
-- John
so it is an interface we cannot have as normal java code, but as at
runtime created class? IMHO interfaces are public by default, so at last
java the language won't work to define the interface... but won't stop
us of course.
> Even if it were public, so that random code could grab it and say "foo
> instanceof GroovyInject", the first time it happens for foo's class
> Foo, Groovy would be asked to fill in the GroovyInject methods on
> Foo. Basically, that would be Foo's entry into Groovy-land.
ok, but where does that come from? How does it know it should ask
Groovy? This part is unclear to me, but essential for the whole thing.
If it is done with some kind of registry or bootstrap method, then I
this is a bit of a problem for us, because the object might be asked for
the interface before the bootstrapping is handled. If it is some spi
like infrastructure we have a class loader problem.
But ok, these problems are nullified if the interface is generated at
runtime I guess
> (If for some reason this is too early, and it is a violation of some
> usage rule, then Groovy could defer the question by throwing an error
> of some sort; that would of course terminate the instanceof bytecode
> abnormally.)
>
> After GroovyInject is injected, its getGroovyMeta method would
> (presumably) return a constant customized Groovy metaclass tailored to
> Foo.
constant? well it if it has to return something constant, that is ok for
me, it doesn't hinder us to use our non constant metaclasses ;)
The injected interface would be defined and controlled by Groovy and
On Mar 10, 2009, at 3:07 PM, Jochen Theodorou wrote:
> What if an object comes from Java land into Groovy land and such a
> check
> has happened already?
probably should be package-private.
Even if it were public, so that random code could grab it and say "foo
instanceof GroovyInject", the first time it happens for foo's class
Foo, Groovy would be asked to fill in the GroovyInject methods on
Foo. Basically, that would be Foo's entry into Groovy-land.
(If for some reason this is too early, and it is a violation of some
usage rule, then Groovy could defer the question by throwing an error
of some sort; that would of course terminate the instanceof bytecode
abnormally.)
John Rose schrieb:
> On Mar 10, 2009, at 3:07 PM, Jochen Theodorou wrote:so it is an interface we cannot have as normal java code, but as at
>
>> What if an object comes from Java land into Groovy land and such a
>> check
>> has happened already?
>
> The injected interface would be defined and controlled by Groovy and
> probably should be package-private.
runtime created class? IMHO interfaces are public by default, so at last
java the language won't work to define the interface... but won't stop
us of course.
ok, but where does that come from? How does it know it should ask
> Even if it were public, so that random code could grab it and say "foo
> instanceof GroovyInject", the first time it happens for foo's class
> Foo, Groovy would be asked to fill in the GroovyInject methods on
> Foo. Basically, that would be Foo's entry into Groovy-land.
Groovy? This part is unclear to me, but essential for the whole thing.
If it is done with some kind of registry or bootstrap method, then I
this is a bit of a problem for us, because the object might be asked for
the interface before the bootstrapping is handled. If it is some spi
like infrastructure we have a class loader problem.
> As the prototype is currently implemented it swallows the exception
> and marks the injection as failed.
I don't think that's the right final design. (It's fine for a
prototype.) Swallowing exceptions masks bugs. Better to surface the
exception somehow immediately. It's reasonable to ask the injector to
return normally in most cases.
On Mar 10, 2009, at 4:35 PM, Jochen Theodorou wrote:
> IMHO interfaces are public by default, so at last
> java the language won't work to define the interface... but won't stop
> us of course.
Both Java and the JVM let them be non-public. It is their members
that must be public. The JVM enforces package-private protection on
them.
And as you say they can also be anonymized (partially) by loading into
a special class loader. Some care is required with such techniques,
because class loader constraints will still be enforced, but it should
work in your case, as long as you make only one anonymized interface
with a given name.
On Mar 10, 2009, at 4:35 PM, Jochen Theodorou wrote:
> ok, but where does that come from? How does it know it should ask
> Groovy? This part is unclear to me, but essential for the whole thing.
Groovy defines it, in some package it controls. That's why I called
it GroovyInject. Groovy also defines its injector method.
If Ruby wants to play the same trick, it defines RubyInject and
controls that in a similar way. Anybody can play the game, and there
is no conflict.
...Unless interfaces choose the same name/signature pairs; that's a
feature not a bug. Note that GroovyMeta getMeta() would not conflict
with RubyMeta getMeta(), because of return type signatures.
-- John
Well besides the Sun-VM there is obviously the IBM VM that is important,
because of Websphere. Groovy is also used on JRockit it seems.
I just checked the IBM VM and it seems those fields do exist there as
well, but as array. The problem I reported with SoftReference is now
exactly with that VM... bad.
the method defined on the interface was the missing information, thx to
Tobias
> If Ruby wants to play the same trick, it defines RubyInject and
> controls that in a similar way. Anybody can play the game, and there
> is no conflict.
>
> ...Unless interfaces choose the same name/signature pairs; that's a
> feature not a bug. Note that GroovyMeta getMeta() would not conflict
> with RubyMeta getMeta(), because of return type signatures.
so if there is a getMetaClass() method on the object which returns
groovy.lang.MetaClass and we inject an interface with an method of exact
the same signature, would we then get the implementation from the
interface or the one from the object?
> so if there is a getMetaClass() method on the object which returns
> groovy.lang.MetaClass and we inject an interface with an method of
> exact
> the same signature, would we then get the implementation from the
> interface or the one from the object?
You'd get the one already on the object. No changing information
already specified.
If the object's class already had the interface, you wouldn't be able
to inject it a second time.
If the object's class already had a method (name/sig) of the
interface, you wouldn't be able to inject that particular method, just
the interface and its other methods (if any).
Like the rest of the JVM, this design is consistently monotonic in its
elaboration of class schema information.
-- John
I am in general thinking of doing different modes for groovy... one if
run from the command line and one if run as lib. There are so many
things we could do in case we run from the command line, it is a shame
to not to use them
> It also has the down side that whatever you insert in a given class darn
> well better work across that class across all child classloaders.
true
> So for
> classes loaded at the highest levels, you'd still need some indirection
> to get the appropriate metadata for the "current" Groovy or JRuby
> runtime. It could also be an issue for interface injection, though in
> both cases it may be mitigated by having a separate TypeHolder loaded at
> the lower-level; there would then be multiple entries in the map, and
> the problem is solved. Now you just need to make sure they're cleaned up
> if the child classloader goes away :)
cleaning is a problem too... if we had a single definite exit point in
Groovy we could do different things, but we don't have that...
I see.. so basically we cannot rely on that...
but back to the original problem... if I need to provide the methods and
the interface, how do I get the hard link from the class to the meta
class here? interface injection doesn't seem to allow me to add fields,
only static ones on the interface of course. But that again would mean
that we need one interface type per class. That will be a lot of
classes. In some scenarios several thousand classes. And how is garbage
collection done for these?
> If the object's class already had the interface, you wouldn't be able
> to inject it a second time.
>
> If the object's class already had a method (name/sig) of the
> interface, you wouldn't be able to inject that particular method, just
> the interface and its other methods (if any).
>
> Like the rest of the JVM, this design is consistently monotonic in its
> elaboration of class schema information.
I see... btw.. why does interface injection not bloat the object header?
ah, well I think it is the class header then instead, which should be a
lot less.
bye blackdrag
> how do I get the hard link from the class to the meta
> class here?
Interface injection is (will be) built on top of method handles.
Method handles can close over live data values
(MethodHandles.insertArgument).
So you can inject a one argument method, curried with a tailored
MetaClass value, to fulfill a zero-argument method injection.
That's an interesting facet of runtime injection, making it more
powerful than static injeciton.
-- John
ah, ok, haven't thought of that... and can I use different MethodHandles
for different types I inject into? and does the bootstrapping method for
that include the type I am injecting into? Because I have to let for
example Object return a different value than String.
bye Jochen
John Rose schrieb:
> On Mar 10, 2009, at 6:17 PM, Jochen Theodorou wrote:ah, ok, haven't thought of that... and can I use different MethodHandles
>
>> how do I get the hard link from the class to the meta
>> class here?
>
> Interface injection is (will be) built on top of method handles.
> Method handles can close over live data values
> (MethodHandles.insertArgument).
> So you can inject a one argument method, curried with a tailored
> MetaClass value, to fulfill a zero-argument method injection.
> That's an interesting facet of runtime injection, making it more
> powerful than static injeciton.
for different types I inject into? and does the bootstrapping method for
that include the type I am injecting into? Because I have to let for
example Object return a different value than String.
> John: On the InterfaceInjection wiki page you wrote some things that
> implies that java.lang.Object can not be an injection target. What
> was the motivation behind this?
Hmm... If you don't inject all the way up to object, your untyped
method invocation looks like:
if (x instanceof MyII) ((MyII)x).myIIMethod(); else
MyRuntime.defaultIIMethod(x);
But Groovy or some other language might simply want to inject its
metaclass on every class it encounters. So I retract the restriction.
BTW, the injection is done once for each concrete class encountered,
*and* each superclass thereof. (Not sure that it buys anything to
look at interface supertypes.)
If, say, Object has already been injected, and File is being
considered, the injector has the option to pull down all the methods
injected into Object, or to replace any or all of them. So the
mechanism provides implementation inheritance. As with normal non-
injected interfaces , you are neither prevented from inheriting nor
required to inherit.
-- John
Yes, I was joking. JRuby's continuous integration server runs our tests
against several JVMs:
* Sun Java 5
* Sun Java 6
* OpenJDK 7
* IcedTea JDK 7
* IBM Java 5
* IBM Java 6
* JRockit Java 6
Of those, IBM has given us the most trouble by far. I've added any JVM
against which someone reports a JVM-specific bug, so these are all in
use somewhere.
http://jruby.headius.com:8080/hudson/
- Charlie