graal icon indicating copy to clipboard operation
graal copied to clipboard

[GR-60436] Calling System.getenv() inside an isolate causes a memory leak

Open alexfedorenchik opened this issue 1 year ago • 5 comments

Describe the Issue

Calling System.getenv() inside an isolate causes a memory leak

Using the latest version of GraalVM can resolve many issues.

GraalVM Version

openjdk 21.0.2 2024-01-16 OpenJDK Runtime Environment GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30) OpenJDK 64-Bit Server VM GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30, mixed mode, sharing)

Operating System and Version

Darwin MBPRO 23.6.0 Darwin Kernel Version 23.6.0: Fri Jul 5 17:55:37 PDT 2024; root:xnu-10063.141.1~2/RELEASE_ARM64_T6030 arm64

Troubleshooting Confirmation

Run Command

  1. Run application TEST_LEAK=Hello ./TestLeak
  2. Run leaks command leaks $(pgrep -n TestLeak)

Expected Behavior

No leaks detected

Actual Behavior

Leak detected:

Process:         TestLeak [53536]
Path:            /Users/USER/*/TestLeak
Load Address:    0x102e54000
Identifier:      TestLeak
Version:         0
Code Type:       ARM64
Platform:        macOS
Parent Process:  zsh [18181]

Date/Time:       2024-12-05 09:08:46.120 +0100
Launch Time:     2024-12-05 09:07:55.328 +0100
OS Version:      macOS 14.6 (23G80)
Report Version:  7
Analysis Tool:   /Applications/Xcode.app/Contents/Developer/usr/bin/leaks
Analysis Tool Version:  Xcode 16.1 (16B40)

Physical footprint:         2657K
Physical footprint (peak):  3217K
Idle exit:                  untracked
----

leaks Report Version: 4.0
Process 53536: 525 nodes malloced for 66 KB
Process 53536: 1 leak for 1536 total leaked bytes.

    1 (1.50K) ROOT LEAK: 0x13e808200 [1536]

Steps to Reproduce

  1. create TestLeak class
import java.time.Duration;
import java.time.temporal.ChronoUnit;

import org.graalvm.nativeimage.IsolateThread;
import org.graalvm.nativeimage.Isolates;
import org.graalvm.nativeimage.Isolates.CreateIsolateParameters;
import org.graalvm.nativeimage.c.function.CEntryPoint;
import org.graalvm.nativeimage.c.function.CEntryPoint.IsolateThreadContext;

public class TestLeak {

    public static void main(String[] args) throws InterruptedException {
        System.out.println(System.getenv("TEST_LEAK"));

        var context = Isolates.createIsolate(CreateIsolateParameters.getDefault());
        isolate(context);
        Isolates.tearDownIsolate(context);

        System.out.println("Run 'leaks $(pgrep -n TestLeak)' to see leak");
        Thread.sleep(Duration.of(1, ChronoUnit.MINUTES));
    }

    @CEntryPoint
    private static void isolate(@IsolateThreadContext IsolateThread context) {
        System.out.println(System.getenv("TEST_LEAK"));
    }
}
  1. Build native image echo "Main-Class: TestLeak" > manifest.txt && javac TestLeak.java && jar -cvfm TestLeak.jar manifest.txt TestLeak.class && native-image -jar TestLeak.jar
  2. Run app TEST_LEAK=Hello ./TestLeak
  3. In a separate terminal run leaks leaks $(pgrep -n TestLeak)

Additional Context

No response

Run-Time Log Output and Error Messages

No response

alexfedorenchik avatar Dec 05 '24 08:12 alexfedorenchik

Hi @alexfedorenchik,

Thank you for reaching out to us! I can see that you're using GraalVM CE 21.0.2+13.1 which is not the latest version of GraalVM. Could you please try testing with the latest version? You can find it here: https://github.com/graalvm/graalvm-ce-builds/releases/

selhagani avatar Dec 05 '24 15:12 selhagani

java --version

openjdk 23.0.1 2024-10-15
OpenJDK Runtime Environment GraalVM CE 23.0.1+11.1 (build 23.0.1+11-jvmci-b01)
OpenJDK 64-Bit Server VM GraalVM CE 23.0.1+11.1 (build 23.0.1+11-jvmci-b01, mixed mode, sharing)

build app:

(base) afedorenchik@MBPRO test % echo "Main-Class: TestLeak" > manifest.txt && javac TestLeak.java &&  jar -cvfm TestLeak.jar manifest.txt TestLeak.class && native-image -jar TestLeak.jar
added manifest
adding: TestLeak.class(in = 1784) (out= 829)(deflated 53%)
========================================================================================================================
GraalVM Native Image: Generating 'TestLeak' (executable)...
========================================================================================================================
[1/8] Initializing...                                                                                    (3.4s @ 0.09GB)
 Java version: 23.0.1+11, vendor version: GraalVM CE 23.0.1+11.1
 Graal compiler: optimization level: 2, target machine: armv8-a
 C compiler: cc (apple, arm64, 16.0.0)
 Garbage collector: Serial GC (max heap size: 80% of RAM)
 1 user-specific feature(s):
 - com.oracle.svm.thirdparty.gson.GsonFeature
------------------------------------------------------------------------------------------------------------------------
Build resources:
 - 26.49GB of memory (73.6% of 36.00GB system memory, determined at start)
 - 12 thread(s) (100.0% of 12 available processor(s), determined at start)
[2/8] Performing analysis...  [****]                                                                     (3.7s @ 0.30GB)
    3,300 reachable types   (70.7% of    4,670 total)
    3,849 reachable fields  (44.2% of    8,713 total)
   15,533 reachable methods (44.5% of   34,895 total)
    1,045 types,    13 fields, and   140 methods registered for reflection
       57 types,    56 fields, and    52 methods registered for JNI access
        4 native libraries: -framework Foundation, dl, pthread, z
[3/8] Building universe...                                                                               (0.7s @ 0.33GB)
[4/8] Parsing methods...      [*]                                                                        (0.4s @ 0.35GB)
[5/8] Inlining methods...     [***]                                                                      (0.4s @ 0.41GB)
[6/8] Compiling methods...    [**]                                                                       (3.8s @ 0.37GB)
[7/8] Laying out methods...   [*]                                                                        (0.8s @ 0.43GB)
[8/8] Creating image...       [*]                                                                        (0.9s @ 0.49GB)
   5.04MB (39.76%) for code area:     8,872 compilation units
   7.25MB (57.17%) for image heap:   94,988 objects and 72 resources
 398.26kB ( 3.07%) for other data
  12.68MB in total
------------------------------------------------------------------------------------------------------------------------
Top 10 origins of code area:                                Top 10 object types in image heap:
   3.79MB java.base                                            1.37MB byte[] for code metadata
 905.85kB svm.jar (Native Image)                               1.27MB byte[] for java.lang.String
 109.50kB java.logging                                       933.09kB java.lang.String
  61.95kB org.graalvm.nativeimage.base                       785.58kB java.lang.Class
  47.16kB jdk.proxy2                                         283.59kB com.oracle.svm.core.hub.DynamicHubCompanion
  37.66kB jdk.proxy1                                         281.04kB byte[] for general heap data
  20.63kB org.graalvm.collections                            255.70kB java.util.HashMap$Node
  19.18kB jdk.internal.vm.ci                                 195.54kB java.lang.Object[]
  11.54kB jdk.proxy3                                         192.41kB java.lang.String[]
   8.20kB jdk.graal.compiler                                 186.53kB heap alignment
   2.86kB for 4 more packages                                  1.57MB for 938 more object types
------------------------------------------------------------------------------------------------------------------------
Recommendations:
 HEAP: Set max heap for improved and more predictable memory usage.
 CPU:  Enable more CPU features with '-march=native' for improved performance.
------------------------------------------------------------------------------------------------------------------------
                        0.6s (3.8% of total time) in 205 GCs | Peak RSS: 0.94GB | CPU load: 6.72
------------------------------------------------------------------------------------------------------------------------
Build artifacts:
 /Users/afedorenchik/env/repos/cf-executor/test/TestLeak (executable)
========================================================================================================================
Finished generating 'TestLeak' in 14.6s.

Same result:

Process:         TestLeak [77745]
Path:            /Users/USER/*/TestLeak
Load Address:    0x102990000
Identifier:      TestLeak
Version:         0
Code Type:       ARM64
Platform:        macOS
Parent Process:  zsh [18181]

Date/Time:       2024-12-05 17:05:25.915 +0100
Launch Time:     2024-12-05 17:05:19.378 +0100
OS Version:      macOS 14.6 (23G80)
Report Version:  7
Analysis Tool:   /Applications/Xcode.app/Contents/Developer/usr/bin/leaks
Analysis Tool Version:  Xcode 16.1 (16B40)

Physical footprint:         2721K
Physical footprint (peak):  3377K
Idle exit:                  untracked
----

leaks Report Version: 4.0
Process 77745: 525 nodes malloced for 67 KB
Process 77745: 1 leak for 1536 total leaked bytes.

    1 (1.50K) ROOT LEAK: 0x13f808200 [1536]

alexfedorenchik avatar Dec 05 '24 16:12 alexfedorenchik

just to note, this was not reproduced on previous version of graal and jdk

openjdk 17.0.9 2023-10-17
OpenJDK Runtime Environment GraalVM CE 17.0.9+9.1 (build 17.0.9+9-jvmci-23.0-b22)
OpenJDK 64-Bit Server VM GraalVM CE 17.0.9+9.1 (build 17.0.9+9-jvmci-23.0-b22, mixed mode, sharing)

AndreiYu avatar Dec 05 '24 17:12 AndreiYu

I was able to reproduce this issue on my end as well. We will take a closer look into this and I'll make sure to keep you updated.

selhagani avatar Dec 11 '24 10:12 selhagani

We had a quick look at this; to our understanding, System.getenv cannot cause any leaks.

The most likely cause here is that the tool, which is Mac-specific, is somehow not interacting properly with Native Image.

wirthi avatar Jun 11 '25 13:06 wirthi