[ 
https://issues.apache.org/jira/browse/GROOVY-9329?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17469145#comment-17469145
 ] 

Robin edited comment on GROOVY-9329 at 1/7/22, 2:18 AM:
--------------------------------------------------------

Hi, I found the patch Not Really Cached the compiled class.

If we run the next groovy script:
{code:java}
def gcl = new GroovyClassLoader()
def scriptText = 'def x = 1'
gcl.parseClass(scriptText)
def begin = [email protected]()
def clazz = [email protected]().iterator().next()
println clazz.toString() + ", hashCode=" + clazz.hashCode()

3.times { gcl.parseClass(scriptText) }
def end = [email protected]()
def clazz_2 = [email protected]().iterator().next()
println clazz_2.toString() + ", hashCode=" + clazz_2.hashCode()

println(end == begin)
println(clazz == clazz_2)
 {code}
The result is: 
{code:java}
class Script_281961721d66605f3d1f24d294f28232, hashCode=1976401987
class Script_281961721d66605f3d1f24d294f28232, hashCode=1201004240
true
false {code}
clazz != clazz_2, so it means that every time of calling 
"parseClass(scriptText) ", script will be compiled again, then the new class 
put to classCache to replacing the old one.

The fix is: Remove the "gcs.setCachable(false);" line of parseClass(text, 
fileName) in GroovyClassLoader.java
{code:java}
public Class parseClass(final String text, final String fileName) throws 
CompilationFailedException {
    GroovyCodeSource gcs = 
AccessController.doPrivileged((PrivilegedAction<GroovyCodeSource>) () -> new 
GroovyCodeSource(text, fileName, "/groovy/script"));
    gcs.setCachable(false);  <----- Remove the line
    return parseClass(gcs);
} {code}
 

Thanks.

 


was (Author: JIRAUSER283079):
Hi, I found the patch Not Really Cached the compiled class.

If we run the next groovy script:
{code:java}
def gcl = new GroovyClassLoader()
def scriptText = 'def x = 1'
gcl.parseClass(scriptText)def begin = [email protected]()
def clazz = [email protected]().iterator().next()
println clazz.toString() + ", hashCode=" + clazz.hashCode()

3.times { gcl.parseClass(scriptText) }
def end = [email protected]()
def clazz_2 = [email protected]().iterator().next()
println clazz_2.toString() + ", hashCode=" + clazz_2.hashCode()

println(end == begin)
println(clazz == clazz_2)
 {code}
The result is: 
{code:java}
class Script_281961721d66605f3d1f24d294f28232, hashCode=1976401987
class Script_281961721d66605f3d1f24d294f28232, hashCode=1201004240
true
false {code}
clazz != clazz_2, so it means that every time of calling 
"parseClass(scriptText) ", script will be compiled again, then the new class 
put to classCache to replacing the old one.

The fix is: Remove the "gcs.setCachable(false);" line of parseClass(text, 
fileName) in GroovyClassLoader.java
{code:java}
public Class parseClass(final String text, final String fileName) throws 
CompilationFailedException {
    GroovyCodeSource gcs = 
AccessController.doPrivileged((PrivilegedAction<GroovyCodeSource>) () -> new 
GroovyCodeSource(text, fileName, "/groovy/script"));
    gcs.setCachable(false);  <----- Remove the line
    return parseClass(gcs);
} {code}
 

Thanks.

 

> OOME raised while `parseClass(scriptText)`
> ------------------------------------------
>
>                 Key: GROOVY-9329
>                 URL: https://issues.apache.org/jira/browse/GROOVY-9329
>             Project: Groovy
>          Issue Type: Bug
>            Reporter: Daniel Sun
>            Assignee: Daniel Sun
>            Priority: Critical
>             Fix For: 3.0.0-rc-3
>
>          Time Spent: 1h 20m
>  Remaining Estimate: 0h
>
> Many groovy users have encountered the OOME while {{parseClass(scriptText)}} 
> even if the {{scriptText}} has not been changed.
> The cause of the issue is the script file name is generated via 
> {{System.currentTimeMillis()}}, so the script file name will change even if 
> the script text is not changed. As a result, many class instances are created 
> and cached in {{groovy.lang.GroovyClassLoader#classCache}}, the classes can 
> not be GCed, which causes OOME.
> The solution is very simple, the script file name could be generated via md5, 
> which will not change if the script text is not changed.
> {code:java}
> def gcl = new GroovyClassLoader()
> while (true) {
>     gcl.parseClass('def x = 1')
> }
> {code}
> Error message:
> {code:java}
> java.lang.OutOfMemoryError: Compressed class space
>       at ConsoleScript6.run(ConsoleScript6:4)
>       at 
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>       at 
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> {code}



--
This message was sent by Atlassian Jira
(v8.20.1#820001)

Reply via email to