My time here is running up, other things to attend to, so here is what
I wrote about the current state of class loading and garbage collection
in Groovy in the just updated user manual of Grengine:

https://www.grengine.ch/manual.html#the-cost-of-session-separation
--
==== The Cost of Session Separation

Although loading classes from bytecode obtained from compiling Groovy scripts is a lot less expensive than compiling them (plus afterwards also loading the resulting bytecode), it is still somewhat more expensive than one might naively
expect and there are a few things to be aware of when operating that way.

In the following, I will simply call classes compiled by the Groovy compiler
from Groovy scripts/sources _Groovy classes_ and classes compiled by the Java
compiler from Java sources _Java classes_.

* *Class Loading* +
  Experimentally, loading of a typical Groovy class is often about 10 times
  slower than loading a Java class with similarly complex source code, but
  both are relatively expensive operations (of the order of a millisecond
  for a small Groovy class, to give a rough indication). For Java classes,
  this is apparently mainly expensive because some security checks have to
  be made on the bytecode. For Groovy classes, it is mainly expensive
  because some meta information is needed to later efficiently call methods
  dynamically, and the like.
* *Garbage Collection* +
  Classes are stored in _PermGen_ (up to Java 7) resp. _Metaspace_ (Java 8
  and later) plus some associated data on the Heap, at least for Groovy
  classes the latter is normally the case (meta information). Whereas for
  Java classes, unused classes appear to be usually garbage collected from
  PermGen/Metaspace continuously, with Groovy classes this experimentally
  does not happen before PermGen/Metaspace or the Heap reach a configured
limit. Why exactly this is so and whether it is easy to change and whether
  it will change in the future, is difficult to answer for me, I find the
code around it is rather convoluted, hard to untangle. Note that by default
  on Java VMs there is typically no limit set for Metaspace (but there is
for PermGen), so setting a limit is crucial in practice when using Groovy.
* *Garbage Collection Bugs* +
  In the past, several Groovy versions had failed at garbage collecting
  Groovy classes and their class loaders, resulting finally in an
  `OutOfMemoryError` due to exhaustion of PermGen/Metaspace or the Heap,
  whichever limit was reached first. If when you are reading this, Groovy
2.4.6 is (still) the newest version, make sure you set the system property
  `groovy.use.classvalue=true` in the context of Grengine. Note that under
  different circumstances, like the one described in
  https://issues.apache.org/jira/browse/GROOVY-7591[GROOVY-7591:
  Use of ClassValue causes major memory leak] you would instead have had to
  set it to false! That Groovy bug is actually in turn due to a bug in
  Oracle/OpenJDK Java VMs regarding garbage collection under some
  circumstances, more precisely a bug in a new feature (`ClassValue`)
  introduced in order to make thing easier(!) for dynamic languages in the
Java VM, see https://bugs.openjdk.java.net/browse/JDK-8136353[JDK-8136353].

So, if you want to use session separation with Greninge (or otherwise want
to load many Groovy classes repeately), first set a limit on PermGen/Metaspace,
then verify that classes can be garbage collected in an environment close to
production and that throughput under load would be sufficient (despite the
relatively slow class loading performance of Groovy (and Java) classes in the
Java VM) and then use it. And don't forget to repeat this at least when you
upgrade Groovy to a new version, but possibly also when you upgrade Java.

Or see the next section for an alternative...
--

PS: By the way, very funny how Jochen Theodorou "garbage collected" what I
wrote about PhantomReference to a "[...]"...

Good luck with Groovy garbage collection.

Alain

Reply via email to