TL;DR

  • Scenario: Using Guava Cache for local caching in Java projects, with production issues like OOM, abnormal hit rate, thread blocking and performance regression
  • Conclusion: Core issues concentrate on expiration and capacity policy configuration errors, maximumSize/maximumWeight misuse, CacheLoader blocking chain and recordStats abuse
  • Output: A complete troubleshooting path from configuration to monitoring

Version Matrix

ComponentVersion RangeVerified
Guava Cache23.0 – 33.0-jreYes
JDK8, 11, 17Yes
DeploymentSpring Boot 2.x / 3.xYes

Troubleshooting Issues

1. Can it cause OOM?

Situations where Guava Cache may cause OOM:

Scenario 1: Cache never expires or expiration time too long

Cache<String, Object> cache = CacheBuilder.newBuilder()
    .expireAfterWrite(Long.MAX_VALUE, TimeUnit.DAYS)  // Almost never expires
    .build();

Scenario 2: No cache capacity limit or capacity set too large

Cache<String, LargeObject> cache = CacheBuilder.newBuilder()
    .maximumSize(Integer.MAX_VALUE)  // Essentially unlimited
    .build();

2. Will it be cleared immediately upon expiration?

Guava Cache uses lazy cleanup mechanism:

Cleanup Trigger Timing:

  • When executing get() operation to read cache
  • When executing put() operation to write cache
  • When executing size() operation to count cache size

3. maximumSize / maximumWeight misconfiguration causing abnormally low cache hit rate

Root Cause Analysis:

  • maximumSize set too small
  • weight configuration missing

Correct Configuration Suggestions:

Cache<String, Object> cache = CacheBuilder.newBuilder()
    .maximumWeight(102400)
    .weigher((k,v) -> ((String)v).length())
    .recordStats()
    .build();

4. Improper CacheLoader / get usage causing blocking or cascading exceptions

Thread Blocking Issue:

  • When multiple threads concurrently call cache.get(key) for the same uncached key
  • All threads will block waiting for the first thread to complete

5. recordStats abuse + frequent statistics reading

Problem Root Cause Analysis:

  1. recordStats mechanism overhead: Every cache operation requires atomic updates to multiple counters
  2. Problem with frequent statistics reading: Business code frequently calls cache.stats() in critical path

Error Quick Reference

SymptomRoot CauseFix
Heap memory continuously rises until OOMCache never expires or expiration extremely longConfigure reasonable expireAfterWrite and maximumSize for all caches
Configured expiration policy but expired data still occupies memory for longLazy deletion not triggeredCall cache.cleanUp() in scheduled tasks
Cache hit rate consistently below 30%maximumSize set too smallRecalculate maximumSize using “hot key count × safety factor”
Many threads blocked under high concurrencyCacheLoader.load contains slow SQLExtract heavy I/O from load and add rate limiting
QPS drops 5-15% after enabling recordStatsrecordStats maintains atomic counters for every operationEnable recordStats only in pressure testing or troubleshooting environments