When building Java apps that scale, efficient memory usage and performance become critical. Today, weโll look at two powerful (but often underused) tools:
- ๐ WeakHashMap / WeakHashSet โ let the GC clean up what you donโt need
- ๐งฎ Predefining collection sizes โ minimize resizing overhead
Letโs break these down with examples.
๐ WeakHashMap and WeakHashSet: Smart Memory-Friendly Containers
๐ WeakHashMap
in Action
import java.util.Map;
import java.util.WeakHashMap;
public class WeakMapExample {
public static void main(String[] args) {
Map<Object, String> map = new WeakHashMap<>();
Object key = new Object();
map.put(key, "Some value");
System.out.println("Before GC: " + map.size()); // 1
key = null; // Remove strong reference
System.gc(); // Hint the GC to collect
try { Thread.sleep(100); } catch (InterruptedException ignored) {}
System.out.println("After GC: " + map.size()); // Likely 0
}
}
๐ก The key is garbage collected because the map only holds a weak reference to it.
๐งบ Creating a WeakHashSet
import java.util.*;
public class WeakSetExample {
public static void main(String[] args) {
Set<Object> weakSet = Collections.newSetFromMap(new WeakHashMap<>());
Object item = new Object();
weakSet.add(item);
System.out.println("Before GC: " + weakSet.size()); // 1
item = null;
System.gc();
try { Thread.sleep(100); } catch (InterruptedException ignored) {}
System.out.println("After GC: " + weakSet.size()); // Likely 0
}
}
๐ Use case: A cache of objects you donโt want to prevent from being collected.
โ๏ธ Predefining Collection Sizes for Performance
When you know (or can estimate) the number of elements, setting an initial capacity saves time and memory.
๐ Default vs Pre-Sized ArrayList
List<String> dynamicList = new ArrayList<>();
List<String> preSizedList = new ArrayList<>(1000);
for (int i = 0; i < 1000; i++) {
dynamicList.add("Item " + i);
preSizedList.add("Item " + i);
}
โ
The preSizedList
avoids multiple internal array resizes as it grows, leading to:
- Less heap churn
- Fewer GC cycles
- More predictable memory use
Predefining HashMap
Size
Map<Integer, String> map = new HashMap<>(1000);
for (int i = 0; i < 1000; i++) {
map.put(i, "Value " + i);
}
๐ Internally, every resize in HashMap
involves rehashing all entries, which is expensive.
๐งช Benchmark It (Optional but Smart)
If you want to confirm performance gains in your context, try using JMH (Java Microbenchmark Harness). Itโs a great way to test memory usage and execution time differences.
๐งต Recap
Concept | Use It For | Benefits | Watch Out |
---|---|---|---|
WeakHashMap |
Caches, listeners, soft associations | Auto-cleans unused keys | Donโt use for core state |
WeakHashSet |
Temporary or optional references | Prevents memory leaks | Created via Collections.newSetFromMap()
|
Predefined Sizes | Known/estimated data volume | Faster, fewer allocations | Overestimating wastes memory |
๐ฌ Your Turn
Have you used weak references or optimized collection sizing in your projects? What kind of impact did you see? Share in the comments ๐
Top comments (0)