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

Eric Milles commented on GROOVY-10918:
--------------------------------------

Given your example:
{code:groovy}
@groovy.transform.CompileStatic // line 1
String test(String s) {
  s = s.chars().mapToObj{"X"}.collect(Collectors.joining())
  println s.charAt(0)
  s = s.chars().mapToObj{"Y"}.collect(Collectors.joining())
  println s.charAt(0)
  s = s.chars().mapToObj{"Z"}.collect(Collectors.joining())
  println s.charAt(0)
  return s
}
{code}

The bytecode for the method looks like this:
{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  astore_2
     32  aload_2
     33  invokedynamic 2 cast(java.lang.Object) : java.lang.String [61]
     38  astore_1 [s]
     39  aload_2
     40  pop
     41  aload_0 [this]
     42  aload_1 [s]
     43  iconst_0
     44  invokevirtual java.lang.String.charAt(int) : char [122]
     47  invokestatic java.lang.Character.valueOf(char) : java.lang.Character 
[128]
     50  invokevirtual Scratch.println(java.lang.Object) : void [131]
     53  aconst_null
     54  pop
     55  aload_1 [s]
     56  invokevirtual java.lang.String.chars() : java.util.stream.IntStream 
[92]
     59  new Scratch$_test_closure2 [133]
     62  dup
     63  aload_0 [this]
     64  aload_0 [this]
     65  invokespecial Scratch$_test_closure2(java.lang.Object, 
java.lang.Object) [134]
     68  invokedynamic 2 cast(groovy.lang.Closure) : 
java.util.function.IntFunction [100]
     73  invokeinterface 
java.util.stream.IntStream.mapToObj(java.util.function.IntFunction) : 
java.util.stream.Stream [106] [nargs: 2]
     78  invokestatic java.util.stream.Collectors.joining() : 
java.util.stream.Collector [112]
     81  invokeinterface 
java.util.stream.Stream.collect(java.util.stream.Collector) : java.lang.Object 
[118] [nargs: 2]
     86  astore_3
     87  aload_3
     88  invokedynamic 2 cast(java.lang.Object) : java.lang.String [61]
     93  astore_1 [s]
     94  aload_3
     95  pop
     96  aload_0 [this]
     97  aload_1 [s]
     98  iconst_0
     99  invokevirtual java.lang.String.charAt(int) : char [122]
    102  invokestatic java.lang.Character.valueOf(char) : java.lang.Character 
[128]
    105  invokevirtual Scratch.println(java.lang.Object) : void [131]
    108  aconst_null
    109  pop
    110  aload_1 [s]
    111  invokevirtual java.lang.String.chars() : java.util.stream.IntStream 
[92]
    114  new Scratch$_test_closure3 [136]
    117  dup
    118  aload_0 [this]
    119  aload_0 [this]
    120  invokespecial Scratch$_test_closure3(java.lang.Object, 
java.lang.Object) [137]
    123  invokedynamic 2 cast(groovy.lang.Closure) : 
java.util.function.IntFunction [100]
    128  invokeinterface 
java.util.stream.IntStream.mapToObj(java.util.function.IntFunction) : 
java.util.stream.Stream [106] [nargs: 2]
    133  invokestatic java.util.stream.Collectors.joining() : 
java.util.stream.Collector [112]
    136  invokeinterface 
java.util.stream.Stream.collect(java.util.stream.Collector) : java.lang.Object 
[118] [nargs: 2]
    141  astore 4
    143  aload 4
    145  invokedynamic 2 cast(java.lang.Object) : java.lang.String [61]
    150  astore_1 [s]
    151  aload 4
    153  pop
    154  aload_0 [this]
    155  aload_1 [s]
    156  iconst_0
    157  invokevirtual java.lang.String.charAt(int) : char [122]
    160  invokestatic java.lang.Character.valueOf(char) : java.lang.Character 
[128]
    163  invokevirtual Scratch.println(java.lang.Object) : void [131]
    166  aconst_null
    167  pop
    168  aload_1 [s]
    169  areturn
      Line numbers:
        [pc: 0, line: 3]
        [pc: 41, line: 4]
        [pc: 55, line: 5]
        [pc: 96, line: 6]
        [pc: 110, line: 7]
        [pc: 154, line: 8]
        [pc: 168, line: 9]
      Local variable table:
        [pc: 0, pc: 170] local: this index: 0 type: Scratch
        [pc: 0, pc: 170] local: s index: 1 type: java.lang.String
{code}

So it appears to be using local variable slots 2, 3 and 4 to save intermediate 
results before assigning back to "s" (slot 1).

> 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