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

Eric Milles edited comment on GROOVY-10918 at 2/15/23 11:09 PM:
----------------------------------------------------------------

I would guess that javac handles variable assignment without a temporary.  For 
groovyc, a left side variable expression could refer to a dynamic variable, 
local variable, field, setter method or something dynamic.  In order to deal 
with all this, classgen tries to provide a unified approach for multiple 
options.  
https://github.com/apache/groovy/blob/master/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java#L380

I do think I can skip the temp when the target is a local variable (like a 
parameter in this case). 
 I'm trying that out right now.  My experiment produces this, in case you want 
to compare to the previous bytecode output:
{code}
public java.lang.String test(java.lang.String s);
      0  aload_1 [s]
      1  invokevirtual java.lang.String.chars() : java.util.stream.IntStream 
[92]
      4  new Scratch$_test_closure1 [94]
      7  dup
      8  aload_0 [this]
      9  aload_0 [this]
     10  invokespecial Scratch$_test_closure1(java.lang.Object, 
java.lang.Object) [97]
     13  invokedynamic 2 cast(groovy.lang.Closure) : 
java.util.function.IntFunction [100]
     18  invokeinterface 
java.util.stream.IntStream.mapToObj(java.util.function.IntFunction) : 
java.util.stream.Stream [106] [nargs: 2]
     23  invokestatic java.util.stream.Collectors.joining() : 
java.util.stream.Collector [112]
     26  invokeinterface 
java.util.stream.Stream.collect(java.util.stream.Collector) : java.lang.Object 
[118] [nargs: 2]
     31  invokedynamic 2 cast(java.lang.Object) : java.lang.String [61]
     36  astore_1 [s]
     37  aload_1 [s]
     38  pop
     39  aload_0 [this]
     40  aload_1 [s]
     41  iconst_0
     42  invokevirtual java.lang.String.charAt(int) : char [122]
     45  invokestatic java.lang.Character.valueOf(char) : java.lang.Character 
[128]
     48  invokevirtual Scratch.println(java.lang.Object) : void [131]
     51  aconst_null
     52  pop
     53  aload_1 [s]
     54  invokevirtual java.lang.String.chars() : java.util.stream.IntStream 
[92]
     57  new Scratch$_test_closure2 [133]
     60  dup
     61  aload_0 [this]
     62  aload_0 [this]
     63  invokespecial Scratch$_test_closure2(java.lang.Object, 
java.lang.Object) [134]
     66  invokedynamic 2 cast(groovy.lang.Closure) : 
java.util.function.IntFunction [100]
     71  invokeinterface 
java.util.stream.IntStream.mapToObj(java.util.function.IntFunction) : 
java.util.stream.Stream [106] [nargs: 2]
     76  invokestatic java.util.stream.Collectors.joining() : 
java.util.stream.Collector [112]
     79  invokeinterface 
java.util.stream.Stream.collect(java.util.stream.Collector) : java.lang.Object 
[118] [nargs: 2]
     84  invokedynamic 2 cast(java.lang.Object) : java.lang.String [61]
     89  astore_1 [s]
     90  aload_1 [s]
     91  pop
     92  aload_0 [this]
     93  aload_1 [s]
     94  iconst_0
     95  invokevirtual java.lang.String.charAt(int) : char [122]
     98  invokestatic java.lang.Character.valueOf(char) : java.lang.Character 
[128]
    101  invokevirtual Scratch.println(java.lang.Object) : void [131]
    104  aconst_null
    105  pop
    106  aload_1 [s]
    107  invokevirtual java.lang.String.chars() : java.util.stream.IntStream 
[92]
    110  new Scratch$_test_closure3 [136]
    113  dup
    114  aload_0 [this]
    115  aload_0 [this]
    116  invokespecial Scratch$_test_closure3(java.lang.Object, 
java.lang.Object) [137]
    119  invokedynamic 2 cast(groovy.lang.Closure) : 
java.util.function.IntFunction [100]
    124  invokeinterface 
java.util.stream.IntStream.mapToObj(java.util.function.IntFunction) : 
java.util.stream.Stream [106] [nargs: 2]
    129  invokestatic java.util.stream.Collectors.joining() : 
java.util.stream.Collector [112]
    132  invokeinterface 
java.util.stream.Stream.collect(java.util.stream.Collector) : java.lang.Object 
[118] [nargs: 2]
    137  invokedynamic 2 cast(java.lang.Object) : java.lang.String [61]
    142  astore_1 [s]
    143  aload_1 [s]
    144  pop
    145  aload_0 [this]
    146  aload_1 [s]
    147  iconst_0
    148  invokevirtual java.lang.String.charAt(int) : char [122]
    151  invokestatic java.lang.Character.valueOf(char) : java.lang.Character 
[128]
    154  invokevirtual Scratch.println(java.lang.Object) : void [131]
    157  aconst_null
    158  pop
    159  aload_1 [s]
    160  areturn
{code}


was (Author: emilles):
I would guess that javac handles variable assignment without a temporary.  For 
groovyc, a left side variable expression could refer to a dynamic variable, 
local variable, field, setter method or something dynamic.  In order to deal 
with all this, classgen tries to provide a unified approach for multiple 
options.  
https://github.com/apache/groovy/blob/master/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java#L380

I do think I can skip the temp when the target is a local variable (like a 
parameter in this case).  I'm trying that out right now.

> Memory leak: local variable values are not discarded
> ----------------------------------------------------
>
>                 Key: GROOVY-10918
>                 URL: https://issues.apache.org/jira/browse/GROOVY-10918
>             Project: Groovy
>          Issue Type: Bug
>          Components: groovy-runtime
>    Affects Versions: 4.0.9
>            Reporter: Andriy Rysin
>            Priority: Major
>              Labels: MemoryLeak
>         Attachments: TestOOM.groovy, TestOOMIcj.java, TestOOMJ.java, 
> TestOOM_works.groovy, groovy_oom.png
>
>
> When I run the code below with 3 statements with closures inside the method 
> the local var (parameter) values (all 4 of them) are staying in memory.
> I don't see the same problem if I run corresponding Java code with lambdas.
> Run TestOOM.groovy with 
> -Xmx600M -XX:+HeapDumpOnOutOfMemoryError
> Notice groovy fails:
> Y
> Z
> java.lang.OutOfMemoryError: Java heap space
> Dumping heap to java_pid147612.hprof ...
> Heap dump file created [497819587 bytes in 0.136 secs]
> Caught: java.lang.OutOfMemoryError: Java heap space
> java.lang.OutOfMemoryError: Java heap space
>     at test.TestOOM.test(TestOOM.groovy:31)
>     at test.TestOOM.run(TestOOM.groovy:41)
> But Java version does not.
> It looks like all the values of s are still in memory (see screenshot), even 
> though previous values should be discarded.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to