javaadvanced
Weak, Soft, and Phantom References
Use Java reference types for memory-efficient caches, resource cleanup, and GC-aware data structures.
javaPress ⌘/Ctrl + Shift + C to copy
import java.lang.ref.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class ReferenceDemo {
// Soft reference cache — evicted only under memory pressure
static class SoftCache<K, V> {
private final Map<K, SoftReference<V>> cache = new ConcurrentHashMap<>();
public void put(K key, V value) {
cache.put(key, new SoftReference<>(value));
}
public V get(K key) {
SoftReference<V> ref = cache.get(key);
if (ref == null) return null;
V value = ref.get();
if (value == null) cache.remove(key);
return value;
}
public void cleanup() {
cache.entrySet().removeIf(e -> e.getValue().get() == null);
}
public int size() {
cleanup();
return cache.size();
}
}
// Weak reference map — entries removed when key is GC'd
static class WeakRegistry<K, V> {
private final WeakHashMap<K, V> registry = new WeakHashMap<>();
public void register(K key, V value) {
registry.put(key, value);
}
public V lookup(K key) {
return registry.get(key);
}
public int size() { return registry.size(); }
}
// Phantom reference for cleanup tracking
static class CleanupTracker {
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
private final Map<PhantomReference<?>, String> refs = new HashMap<>();
void track(Object obj, String label) {
PhantomReference<Object> phantom = new PhantomReference<>(obj, queue);
refs.put(phantom, label);
}
void processCollected() {
Reference<?> ref;
while ((ref = queue.poll()) != null) {
String label = refs.remove(ref);
System.out.println("Collected: " + label);
ref.clear();
}
}
}
public static void main(String[] args) {
// Soft cache
SoftCache<String, byte[]> cache = new SoftCache<>();
cache.put("img1", new byte[1024 * 1024]); // 1MB
cache.put("img2", new byte[1024 * 1024]);
System.out.println("Cache size: " + cache.size()); // 2
System.out.println("img1: " + (cache.get("img1") != null)); // true
// Weak registry
WeakRegistry<Object, String> registry = new WeakRegistry<>();
Object key = new Object();
registry.register(key, "my-resource");
System.out.println("Before: " + registry.size()); // 1
key = null;
System.gc();
System.out.println("After GC: " + registry.size()); // likely 0
// Phantom tracking
CleanupTracker tracker = new CleanupTracker();
Object resource = new Object();
tracker.track(resource, "db-connection-1");
resource = null;
System.gc();
tracker.processCollected(); // Collected: db-connection-1
}
}Use Cases
- Memory-sensitive caching that adapts to JVM pressure
- Tracking object lifecycle and cleanup
- Avoiding memory leaks in long-lived registries
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
javaintermediate
String Pool and Interning
Understand Java string pooling: intern(), identity vs equality, memory optimization, and common pitfalls.
Best for: Memory optimization for repeated string values
#java#string
javabeginner
Reverse a String in Java
Multiple ways to reverse a string in Java including StringBuilder, char array, and stream approaches.
Best for: String manipulation in coding interviews
#java#string
javabeginner
Read File Line by Line in Java
Read files using BufferedReader, Files.readAllLines, and Stream API with proper resource management.
Best for: Processing log files line by line
#java#file-io
javabeginner
HashMap Operations and Patterns
Essential HashMap operations: put, get, merge, compute, getOrDefault, and iteration patterns.
Best for: Counting word frequencies in text
#java#collections