1

In my project, I use caffeine cache for caching. The configuration is as follows.

 cache = Caffeine.newBuilder()
                .expireAfterWrite(6, TimeUnit.MINUTES)
                .maximumSize(50_0000.get())
                .recordStats()
                .build();

The cache is about 600m.

heap

Usage of read:

ReadOnlyHashTable v = itemPropsCache.getIfPresent(key);

If read miss, then load from redis

// load from redis ...
ReadOnlyHashTable table = new ReadOnlyHashTable('${redisVlue}');
itemPropsCache.setCache(key, table);

After checking the GC logs and JVM heap dump analysis, I found that the old age was growing consistently, resulting in full GC.

The following is my guess: because I set a 6-minute expiration, my cache will produce about 500m of garbage every six minutes in the old generation (because It will be promoted to the old age after reaching MaxTenuringThreshold through the younger generation, and then expire for cleaning).

I have tried CMS and G1 garbage collector, and it seems that they can not reach the ideal state.

CMS:

-server
-Xmx6g
-Xms6g
-XX:NewRatio=1
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
-XX:MaxTenuringThreshold=15
-XX:SurvivorRatio=3
-XX:+ParallelRefProcEnabled
-XX:+CMSParallelRemarkEnabled
-XX:+UseCMSCompactAtFullCollection
-XX:+HeapDumpOnOutOfMemoryError
-XX:MetaspaceSize=512m
-XX:MaxMetaspaceSize=512m
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/export/Logs/gc.log
-XX:+PrintTenuringDistribution

CMS FullGC

G1:

-server
-Xmx6g
-Xms6g
-XX:+UseG1GC
-XX:+HeapDumpOnOutOfMemoryError
-XX:MetaspaceSize=512m
-XX:MaxMetaspaceSize=512m
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/export/Logs/gc.log
-XX:+PrintTenuringDistribution

G1

Is there any solution without adjusting the heap size and cache size?

Thank you!

Feng Kai
  • 21
  • 3
  • Can you please add code how you access and update the cache content? Is the cache size 500k or 500M? – cruftex Jun 18 '22 at 06:53
  • There was a similar question, which I answered extensively: https://stackoverflow.com/questions/71603019/tuning-the-gc-for-large-cache-refresh/71658845 – cruftex Jun 18 '22 at 06:54
  • @cruftex Hi cruftex, 500M, and I have updated code – Feng Kai Jun 18 '22 at 07:32
  • 1
    GCs are not well designed for this workload. You might try to increase the young gen size to accommodate or the threads allocated for marking ([G1 tuning](https://docs.oracle.com/en/java/javase/17/gctuning/garbage-first-garbage-collector-tuning.html#GUID-0DD93225-0BCF-4605-B365-E9833F5BD2FC)). This case may better fit an off-heap cache like [OHC](https://github.com/snazy/ohc) or [ChronicleMap](https://github.com/OpenHFT/Chronicle-Map), as you preallocate memory for reuse. – Ben Manes Jun 18 '22 at 16:04
  • 1
    What is “the ideal state” you are trying to reach? – Holger Jun 20 '22 at 09:32
  • @Holger The less 'full gc' the better, it is better to reduce to one full GC in a day – Feng Kai Jun 20 '22 at 11:05
  • 1
    How do you determine that you actually have a a Full GC? A G1GC Mixed collection is not a Full GC. – Holger Jun 20 '22 at 12:12

0 Answers0