Skip to main content
Caffeine automatically evicts entries to maintain size constraints and responds to memory pressure through reference-based eviction.

Size-based eviction

Limit the cache by maximum number of entries or total weight.

Maximum size

Evict entries when the cache exceeds a maximum number:
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

Cache<String, Document> cache = Caffeine.newBuilder()
    .maximumSize(10_000)
    .build();
When maximumSize is 0, entries are evicted immediately after loading. This is useful for testing or temporarily disabling caching.
Reference: Caffeine.java:425

Maximum weight

Evict entries based on cumulative weight using a custom Weigher:
import com.github.benmanes.caffeine.cache.Weigher;

Cache<String, Document> cache = Caffeine.newBuilder()
    .maximumWeight(100_000)
    .weigher((key, document) -> document.sizeInBytes())
    .build();
Reference: Caffeine.java:462, Caffeine.java:504
maximumSize() and maximumWeight() are mutually exclusive. You must use weigher() with maximumWeight().

Custom weigher

Implement Weigher for complex weight calculations:
Weigher<String, Document> weigher = new Weigher<>() {
    @Override
    public int weigh(String key, Document value) {
        // Weight based on both key and value
        return key.length() + value.sizeInBytes();
    }
};

Cache<String, Document> cache = Caffeine.newBuilder()
    .maximumWeight(100_000)
    .weigher(weigher)
    .build();
Weight must be non-negative. Weights are measured when entries are inserted or updated and remain static during the entry’s lifetime.
Reference: Weigher.java:45

Eviction policy

Caffeine uses the Window TinyLFU eviction policy, which combines recency and frequency to maximize hit rate.

How it works

New entries enter a probationary space (the “window”) where they are evaluated based on recent access patterns. This protects against cache pollution from one-hit-wonders.

Accessing eviction policy

Inspect and control eviction behavior:
import com.github.benmanes.caffeine.cache.Policy.Eviction;

Cache<String, Document> cache = Caffeine.newBuilder()
    .maximumSize(10_000)
    .build();

cache.policy().eviction().ifPresent(eviction -> {
    // Check if weighted
    boolean weighted = eviction.isWeighted();
    
    // Get current maximum
    long max = eviction.getMaximum();
    
    // Change maximum at runtime
    eviction.setMaximum(20_000);
    
    // Get weight of specific entry
    eviction.weightOf("key").ifPresent(weight -> 
        System.out.println("Weight: " + weight)
    );
    
    // Get total weight
    eviction.weightedSize().ifPresent(size -> 
        System.out.println("Total weight: " + size)
    );
});
Reference: Policy.java:158

Eviction order inspection

View entries ordered by likelihood of eviction:
import java.util.Map;

cache.policy().eviction().ifPresent(eviction -> {
    // Get coldest entries (most likely to be evicted)
    Map<String, Document> coldest = eviction.coldest(100);
    
    // Get hottest entries (least likely to be evicted)
    Map<String, Document> hottest = eviction.hottest(100);
    
    // For weighted caches
    Map<String, Document> coldestWeighted = 
        eviction.coldestWeighted(10_000);
});
Reference: Policy.java:224, Policy.java:291
Obtaining ordered views is not a constant-time operation. It requires traversing entries within the eviction policy’s exclusive lock.

Reference-based eviction

Automatically evict entries when keys or values are garbage collected.

Weak keys

Keys wrapped in weak references are evicted when garbage collected:
Cache<String, Document> cache = Caffeine.newBuilder()
    .weakKeys()
    .maximumSize(10_000)
    .build();
With weakKeys(), the cache uses identity (==) comparison for keys instead of equals(), similar to IdentityHashMap.
Reference: Caffeine.java:557

Weak values

Values wrapped in weak references are evicted when garbage collected:
Cache<String, Document> cache = Caffeine.newBuilder()
    .weakValues()
    .maximumSize(10_000)
    .build();
Weak values are garbage collected as soon as they become weakly reachable, making them poor candidates for caching. Consider softValues() instead.
Reference: Caffeine.java:587

Soft values

Values wrapped in soft references are garbage collected in response to memory pressure:
Cache<String, Document> cache = Caffeine.newBuilder()
    .softValues()
    .maximumSize(10_000)
    .build();
Soft references are garbage collected using a globally LRU manner when the JVM needs memory.
In most cases, it’s better to use maximumSize() instead of soft references. Only use soft references if you understand their performance implications.
Reference: Caffeine.java:624

Eviction timing

Understand when eviction maintenance occurs:

Automatic maintenance

Eviction is performed opportunistically:
  • During write operations (most common)
  • During read operations when writes are absent
  • Via calls to cleanUp()
// Manually trigger maintenance
cache.cleanUp();
Reference: Cache.java:221

Batch operations

Eviction is batched for efficiency:
// Eviction may occur during writes
cache.put("key1", value1);
cache.put("key2", value2);
cache.putAll(Map.of("key3", value3, "key4", value4));

Best practices

  • Set maximumSize based on expected working set size
  • Use maximumWeight when entries have significantly different sizes
  • Monitor cache statistics to tune the maximum
  • Remember that the cache may temporarily exceed the maximum during eviction
  • Return 0 weight for entries that should not count toward eviction
  • Keep weight calculations fast (they run on every insert/update)
  • Ensure weights are non-negative
  • Consider both key and value sizes if memory is constrained
  • Prefer maximumSize over reference-based eviction when possible
  • Use weakKeys() for canonicalization or interning use cases
  • Use softValues() only if you need memory-sensitive caching
  • Avoid weakValues() unless you have specific requirements
  • Adjust maximumSize or maximumWeight at runtime via the policy API
  • Call cleanUp() if you need prompt eviction after size changes
  • Monitor evictionCount in statistics to understand churn

Build docs developers (and LLMs) love