Java – groovy classes are not collected, but there are no signs of memory leaks
I have a Java class that dynamically reloads groovy classes using a custom class loader. I see some strange behaviors. Some classes are not collected, but it will not leak memory over time (for example, perm Gen will not continue to grow indefinitely)
In my java code, I am loading such a class (the template file is deleted for simplicity):
Class clazz = groovyClassLoader.loadClass(className,true,false,true); instance = clazz.newInstance();
Then I dynamically reload the groovy class by clearing the class loader cache, metaregistry, etc.:
for (Class c : groovyClassLoader.getLoadedClasses()){ GroovySystem.getMetaClassRegistry().removeMetaClass(c); } groovyClassLoader.clearCache();
Now, if I just loop through the code, load and reload my groovy classes, I will see strange behavior (my test code is actually just a loop overloading process - it doesn't do anything to any created objects, so the instances in the above code are only local, so it should be good for GC)
If I run it and set maxpermsize to 128M, then I get the leak behavior and oom permgen error:
However, if I run it again and increase maxpermsize to 256M, everything is fine. It can run forever (this image is 1 hour, but I have run it all night and done thousands of reloads):
Has anyone experienced any similar behavior? Or do you have any ideas? In the first example, it also seems strange that memory utilization increases gradually rather than steadily
Solution
The zigzag pattern you see is usually a typical feature of memory allocation and release You added code to clear the cache, but this does not mean that the class will be collected JVMs tend to add a lot of memory before attempting normal garbage collection for longer life objects Deleting classes is less work, usually only during the full GC run This can lead to a nasty situation where permgen is full and oome is thrown, even if the class has been collected The exact behavior seems to vary from version to version
in any case. Just because the class is no longer referenced does not mean that it is collected immediately Instead, permgen may grow to the maximum and unload the class
In addition to your loadclass call that may lead to the creation of a new class and the metaclass registry that references the class in some way, there are more classes that may be referenced For example, the call point cache in groovy also involves softreferences If reflection calls something often (groovy may have to do this), auxiliary classes may be generated to speed up reflection The latter is done by JDK, not groovy
I have to make a correction: metaclasses are not real classes, nor can they use permgen But they refer to classes with permgen Therefore, if a metaclass is difficult to reference, the class remains unchanged There is an interesting "feature" in IBM JDK. If it is hard referenced, it does treat a class as uninstallable, even if the object executing the reference itself is part of softreference
In order to explain the above behavior more completely, I need the output of the JVM for class loading and unloading I think the application can theoretically run 128MB If you look at the 128MB chart at the low point before 16:17:30 and the previous position, you may notice that the previous one is not as low as the other This means that the point before the time code unloads more classes than the previous point The JVM is free to decide when to delete a class and does not always delete all classes that can theoretically be unloaded You have to trade off between classes that can be unloaded under performance