5

Could you kindly help us with a query we have regarding a Java 8 Spring boot application running in Docker containers in ECS? After migrating to Java 17, we observed a significant 1GB increase in memory usage of the container as compared to the memory usage of the container running on Java 8 (we compared the memory using the docker stats command for both the containers). We only have the Java process running inside the container. The jmap command output from both Java 8 and Java 17 are provided below. The only significant changes we observed are that:

  1. The Garbage collection algorithm is G1, which is now the default in Java 17, as compared to CMS in Java 8.
  2. The MaxNewSize has increased from 166.375MB in Java 8 to 1228.0MB in Java 17.

We would like to know if this is the reason for the increased memory usage in the Docker container. We understand that the new G1 garbage collection algorithm has slightly higher memory usage (around 120 MB, as compared to 12 MB for CMS, as found from the jcmd VM.native_memory command output), but we were not expecting such a drastic increase. Any suggestions or insights on this issue would be greatly appreciated.

jmap output for Java 8

using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 2147483648 (2048.0MB)
   NewSize                  = 174456832 (166.375MB)
   MaxNewSize               = 174456832 (166.375MB)
   OldSize                  = 1973026816 (1881.625MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 157024256 (149.75MB)
   used     = 135629568 (129.346435546875MB)
   free     = 21394688 (20.403564453125MB)
   86.37491522328881% used
Eden Space:
   capacity = 139591680 (133.125MB)
   used     = 131489752 (125.39839935302734MB)
   free     = 8101928 (7.726600646972656MB)
   94.19598073466842% used
From Space:
   capacity = 17432576 (16.625MB)
   used     = 4139816 (3.9480361938476562MB)
   free     = 13292760 (12.676963806152344MB)
   23.747586128406954% used
To Space:
   capacity = 17432576 (16.625MB)
   used     = 0 (0.0MB)
   free     = 17432576 (16.625MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 1973026816 (1881.625MB)
   used     = 73134816 (69.74679565429688MB)
   free     = 1899892000 (1811.8782043457031MB)
   3.706731981893144% used

38981 interned Strings occupying 3969216 bytes.

jmap output for Java 17

using thread-local object allocation.
Garbage-First (G1) GC with 2 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 2147483648 (2048.0MB)
   NewSize                  = 1363144 (1.2999954223632812MB)
   MaxNewSize               = 1287651328 (1228.0MB)
   OldSize                  = 5452592 (5.1999969482421875MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 1048576 (1.0MB)

Heap Usage:
G1 Heap:
   regions  = 2048
   capacity = 2147483648 (2048.0MB)
   used     = 1115684864 (1064.0MB)
   free     = 1031798784 (984.0MB)
   51.953125% used
G1 Young Generation:
Eden Space:
   regions  = 977
   capacity = 1312817152 (1252.0MB)
   used     = 1024458752 (977.0MB)
   free     = 288358400 (275.0MB)
   78.03514376996804% used
Survivor Space:
   regions  = 38
   capacity = 39845888 (38.0MB)
   used     = 39845888 (38.0MB)
   free     = 0 (0.0MB)
   100.0% used
G1 Old Generation:
   regions  = 50
   capacity = 794820608 (758.0MB)
   used     = 50331648 (48.0MB)
   free     = 744488960 (710.0MB)
   6.332453825857519% used

43272 interned Strings occupying 4300576 bytes. 

JVM options used for Java 8:

-server -Xms2048m -Xmx2048m -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails

JVM options for Java 17:

-server -Xms2048m -Xmx2048m -XX:+UseG1GC -Xlog:gc*
Rohan Bhattacharya
  • 375
  • 1
  • 5
  • 13
  • You should create heap dumps and look at what is using all the memory. – marstran May 03 '23 at 07:18
  • @marstran We did do that, but did not find any significant differences in the amount of objects that is getting generated between Java 8 and Java 17. And we have this memory increased right from the start of the container. So we wanted to know if this was the behavior when G1 is used. – Rohan Bhattacharya May 03 '23 at 07:26
  • The difference of `MaxNewSize` is irrelevant, those are (or could be) dynamically tuned by the JVM itself. The NewSize + OldSize will always be <= MaxHeapSize (as will MaxNewSize + OldSize). What was the total memory size under Java 8, and what is the total memory size under Java 17. What are the JVM options used to launch your application? – Mark Rotteveel May 03 '23 at 07:26
  • Thank you @MarkRotteveel. I have updated the JVM options used in the question. But, by total memory are you referring to the heap memory allocated? It was 2GB in both the cases. As for docker stats results, it was 618.1MiB in case of Java 8 and 1.693GiB in case of Java 17. – Rohan Bhattacharya May 03 '23 at 07:40
  • If the difference is 1.693GiB vs 618MiB, that 1GB difference could just be a difference in how memory is initially allocated. That is, if you had really used all 2GiB heap, your process memory would be > 2GiB in both cases. – Mark Rotteveel May 03 '23 at 07:48
  • @MarkRotteveel -- Exactly! and that is what we needed an advise on, as we could not find any official document stating the same - that G1, as compared to CMS, initially allocates this much chunk of memory. We found, compared to CMS, G1 allocates a much bigger young generation. But we wanted to know if this is allocated right from the start. – Rohan Bhattacharya May 03 '23 at 07:56

1 Answers1

1

We are facing the same Problem. The Docker Images have doubled there memory consumption after switching from JDK11 to JDK 17.

Our "old" JDK 11 was with OpenJ9 VM

FROM adoptopenjdk/openjdk12-openj9

and we switched to

FROM eclipse-temurin:17-jdk

The Eclipse-Temurin uses the hotspot vm instead of openj9. After switching to a JDK 17 with OpenJ9 the Problems are gone.

We now use

FROM ibm-semeru-runtimes:open-17-jdk-focal (which has OpenJ9 VM as default)

and it works like expected.