0

in my demo project,

69.741: [Full GC (Allocation Failure) 1023M->1023M(1024M), 1.1631632 secs]

about 30+ times, then throw OOM, about 1min.

the same jvm params, the same code. in my online project(has zk, nacos,es,rabbit,actuator...) about 5min+ then throw OOM

i want fast fail,can free memory fast, so what`s problem in my online project. what can i do?

i also try change java version(jdk-11.0.13 and 1.8.0_301), it`s the same result

the same jvm param

java -server -Xmx1024m -Xms1024m -Dapp.key=rrr -Dspring.profiles.active=docker -DskipTests -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Duser.timezone=GMT+8 -Djava.net.preferIPv6Addresses=false -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -Xloggc:./gcdemo.log -XX:+PrintHeapAtGC -Ddubbo.registry.address=*.* -jar ./demo3-0.0.1-SNAPSHOT.jar

the same code is

    public Object ttttttsss() {

        List s = new LinkedList();
        while (true) {
            String uuid = UUID.randomUUID().
                    toString();
            uuid = uuid + uuid + uuid + uuid;
            s.add(uuid);
        }

    }
perfect
  • 1
  • 1
  • i think should throw java.lang.OutOfMemoryError:GC overhead limit exceeded because its cost 98% time doing garbage collection and recovering less than 2% of the heap – perfect Jan 15 '22 at 01:40
  • 1
    That's not how that option works. Read the documentation. And you don't appear to have enabled it anyway. – Stephen C Jan 15 '22 at 01:43
  • 1
    “because its cost 98% time doing garbage collection”—the problem with this relation is, the slower your actual program, the more time is allowed for garbage collection. And `UUID.randomUUID()` settles on `SecureRandom` which is *very* slow. And string concatenation isn’t a fast thing either. It further produces garbage which the GC can recycle successfully. – Holger Jan 17 '22 at 15:50

1 Answers1

2

You are filling up the heap with a ginormous list. The GC tries, and tries, and tries to keep going. But eventually it hits the max heap size and you get an OOME.

The reason that the app gets slower is that you are spending more and more time garbage collecting.

Why?

Because the time taken to run the GC is roughly proportional to the size of the non-garbage objects. And since you will have an ever larger number of non-garbage (i.e. reachable) objects in your list, the GC runs will take longer each time.

In addition, the time between each GC run reduces, since the GC is able to find reducing amounts of garbage each time. Eventually the JVM is spending all of its time in futile garbage collection ... and then it can't go any further and it throws an OOME.

This pattern of behavior is sometimes called a "GC death spiral".

If you want the JVM to avoid wasting time in futile GC's and fail faster, then set the -XX:+UseGCOverheadLimit option. This tells the JVM to throw an OOME if the percentage of time spent running the GC exceeds a configurable threshold. You can find more details in the Oracle Java documentation. Including how to alter the thresholds.

Resources:


+UseGCOverheadLimit That should be the default configuration in jvm ?

It is (IIRC) version dependent whether that option is enabled by default. (So set it explicitly!)

I remember I use this config but the result is poor.

It depends on what you mean by that.

However, there is a clear trade-off between sometimes throwing the OOME too early, and allowing repeated GC's to bring the JVM to its knees. Unfortunately the JVM cannot make the best choice in all cases. (It would require it to be able to precidely predict how much memory the application is going to need. That is clearly impractical.)

Anyhow +UseGCOverheadLimit, increasing the max heap size, and/or fixing your application to use less heap memory are the only possible things you can do to address this behavior.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • ”+UseGCOverheadLimit“ That should be the default configuration in jvm ? i remember i use this config but the result is poor – perfect Jan 15 '22 at 01:43
  • 1
    Well yea ... you need to choose whether you want fail faster or fail less often. – Stephen C Jan 15 '22 at 01:46
  • 1
    There is an option you can provide that tells you all of the options that are actually used by the JVM. (Don't just rely on your memory of the defaults. They are complicated and are liable to change from one Java release to the next.) – Stephen C Jan 15 '22 at 01:47
  • i try find more config information in Oracle Java documentation, but not my expect. – perfect Jan 15 '22 at 01:47
  • 1
    Keep looking. It isn't all in the one place. – Stephen C Jan 15 '22 at 01:48
  • ook, i try config more about my jvm params. but i originally wanted the jvm automatic adjustment. After all, it is also a new feature. i try config more detail, thank you – perfect Jan 15 '22 at 01:52
  • 1
    If you are talking about `-XX:+UnlockExperimentalVMOptions`, that is irrelevant to the problem you are experiencing. You need to read the documentation *carefully* about what it does. In fact, by itself it will have no effect at all. GC tuning is complicated and it requires you to read the documentation carefully. Just skim reading random web pages and randomly setting options won't work. – Stephen C Jan 15 '22 at 01:54
  • 1
    The option is turned on by default, but has no effect when using `G1GC`. See [Is UseGCOverheadLimit supported with G1 GC?](https://stackoverflow.com/q/45925980/2711488) – Holger Jan 17 '22 at 15:58