Reputation: 1
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
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:
https://docs.oracle.com/en/java/javase/17/gctuning/introduction-garbage-collection-tuning.html
The manual page for the specific version the java
command you are using will list the most common GC tuning options.
+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