perfect
perfect

Reputation: 1

jvm G1 ,The memory is full, full gc and fail has many many times , then throw OOM , 5min or more, cost a long time ,why?

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);
        }

    }

Upvotes: 0

Views: 746

Answers (1)

Stephen C
Stephen C

Reputation: 718916

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.

Upvotes: 2

Related Questions