# Part 13 — Performance & Memory Tuning (Senior Java)
This is where senior-level interviews become noticeably different from mid-level interviews.
A junior developer might know:
"
HashMaplookup is O(1)."
A senior developer should also explain:
- When O(1) degrades
- Why pre-sizing matters
- How GC is affected
- What memory trade-offs exist
- Which collection is best for a specific workload
Typical interview questions:
- Which collection is most memory efficient?
- Why is
LinkedListrarely used? - How do you tune
HashMap? - Why specify initial capacity?
- How does cache locality affect performance?
- Which collection would you choose for millions of records?
1. Big-O Complexity Overview¶
| Collection | get | add | remove | contains |
|---|---|---|---|---|
| ArrayList | O(1) | O(1)* | O(n) | O(n) |
| LinkedList | O(n) | O(1)** | O(1)** | O(n) |
| HashSet | O(1) | O(1) | O(1) | O(1) |
| HashMap | O(1) | O(1) | O(1) | O(1) |
| TreeMap | O(log n) | O(log n) | O(log n) | O(log n) |
| TreeSet | O(log n) | O(log n) | O(log n) | O(log n) |
| PriorityQueue | O(1)* | O(log n) | O(log n) | O(n) |
- Amortized; resize operations are O(n).
** Assuming you already have a reference to the node (or are operating at the head/tail where applicable).
*** peek() is O(1); removing the head (poll()) is O(log n).
2. ArrayList Memory Layout¶
Internally:
ArrayList
↓
Object[]
↓
A B C D E
Advantages:
- Contiguous memory
- Excellent CPU cache locality
- Fast iteration
- Minimal per-element overhead
3. LinkedList Memory Layout¶
Node
↓
prev
↓
data
↓
next
Each element requires:
- Data reference
- Previous reference
- Next reference
- Separate node object
Much higher memory overhead than ArrayList.
4. Cache Locality¶
Interview favorite.
CPU cache prefers contiguous memory.
Example:
ArrayList
A B C D E
Memory:
100
101
102
103
Sequential access benefits from hardware prefetching.
LinkedList:
Node
↓
500
↓
1000
↓
200
↓
900
Nodes may be scattered across memory.
More cache misses.
Result¶
Although both loops are O(n):
for (...)
ArrayList is usually much faster than LinkedList in real applications due to better cache locality.
5. Why LinkedList Is Rarely Used¶
Interview favorite.
Many assume:
Insertion O(1)
Therefore:
LinkedList faster
Wrong.
Reality:
To insert in the middle:
Find node
↓
O(n)
Then:
Insert
↓
O(1)
Overall:
O(n)
Combined with poor cache locality and higher memory usage, LinkedList is often slower than ArrayList.
6. HashMap Capacity¶
Default:
new HashMap<>();
Internally:
Capacity = 16
Load Factor = 0.75
Threshold = 12
After 12 entries:
Resize
↓
32
7. Resize Cost¶
Resize process:
Allocate larger table
↓
Recompute bucket locations
↓
Transfer entries
Complexity:
O(n)
Frequent resizing hurts performance.
8. Initial Capacity Tuning¶
Suppose:
Expected entries
↓
1,000,000
Bad:
new HashMap<>();
Many resize operations.
Better:
new HashMap<>(1_400_000);
The goal is to reduce or eliminate resizing.
A commonly used estimate is:
capacity ≈ expectedEntries / loadFactor
For a load factor of 0.75:
1,000,000 / 0.75 ≈ 1,333,334
The implementation rounds to an appropriate power of two internally.
9. Load Factor¶
Default:
0.75
Meaning:
75% full
↓
Resize
Trade-offs:
Low load factor:
- More memory
- Fewer collisions
High load factor:
- Less memory
- More collisions
0.75 is a practical balance for most applications.
10. Hash Collision Impact¶
Worst case:
Bucket
↓
Linked List
↓
Many entries
Lookup:
O(n)
Java 8:
Linked List
↓
Red-Black Tree
↓
O(log n)
Treeification improves worst-case performance when many keys collide.
11. HashSet Performance¶
Internally:
HashMap
Therefore:
contains()add()remove()
Average:
O(1)
12. TreeMap Performance¶
Internally:
Red-Black Tree
Every operation:
O(log n)
Use it only when sorted order is required.
13. Queue Performance¶
ArrayDeque
Operations at both ends:
O(1)
Preferred over:
LinkedList
for stack and queue implementations.
14. Memory Comparison¶
Approximate ranking:
Least memory
↓
ArrayList
↓
HashMap
↓
TreeMap
↓
LinkedList
↓
Most memory
Exact memory depends on:
- JVM implementation
- Object alignment
- Pointer compression
- Key/value types
15. GC Impact¶
Millions of LinkedList nodes:
Millions
↓
Individual objects
Garbage Collector:
Must trace every node
ArrayList:
One array
↓
Much fewer objects
Generally less GC overhead.
16. Object Allocation¶
Creating:
1 million LinkedList nodes
allocates roughly:
1 million objects
ArrayList:
One backing array
plus the element objects themselves.
Fewer allocations typically improve throughput.
17. Choosing the Right Collection¶
| Requirement | Collection |
|---|---|
| Fast random access | ArrayList |
| Fast lookup | HashMap |
| Unique elements | HashSet |
| Sorted data | TreeMap |
| Priority scheduling | PriorityQueue |
| Thread-safe map | ConcurrentHashMap |
| Read-heavy list | CopyOnWriteArrayList |
18. Production Scenario¶
Suppose:
10 million users
↓
Lookup by ID
Bad:
LinkedList
Good:
HashMap
Reason:
O(1)
average lookup.
19. Another Scenario¶
Need:
Top 100 salaries
Bad:
ArrayList
↓
Sort every time
Better:
PriorityQueue
Maintain only the top elements efficiently.
20. Yet Another Scenario¶
Need:
Sorted keys
Use:
TreeMap
Not:
HashMap
because HashMap does not maintain sorted order.
21. Benchmarking¶
Never rely on intuition.
Measure.
For Java microbenchmarks, use JMH (Java Microbenchmark Harness) rather than writing loops with System.nanoTime().
Naive benchmarks are often misleading due to:
- JIT compilation
- Dead-code elimination
- Escape analysis
- CPU warm-up effects
22. Common Optimization Mistakes¶
Mistake 1¶
Using:
LinkedList
because insertion is O(1).
Ignoring traversal cost.
Mistake 2¶
Using:
new HashMap<>();
for a map expected to hold millions of entries.
Ignoring resize overhead.
Mistake 3¶
Using:
TreeMap
when ordering is unnecessary.
Paying O(log n) instead of average O(1).
Mistake 4¶
Using:
Vector
instead of:
ArrayList
without requiring synchronization.
23. Performance Summary¶
| Collection | Strength | Weakness |
|---|---|---|
| ArrayList | Fast iteration, random access | Middle insert/remove |
| LinkedList | Efficient head/tail insertion/removal | Memory, cache locality, traversal |
| HashMap | Average O(1) lookup | No ordering |
| TreeMap | Sorted keys | O(log n) operations |
| PriorityQueue | Efficient priority handling | No random access |
Production Examples¶
User Cache¶
Map<Long, User> cache =
new HashMap<>(1_500_000);
Avoid repeated resizing.
Read-Mostly Configuration¶
List<String> config =
List.copyOf(source);
Immutable and safe to share.
Task Scheduler¶
PriorityQueue<Task>
Efficiently retrieves the next task.
Product Search¶
TreeMap<String, Product>
Useful when sorted keys or range queries are required.
Common Interview Questions¶
Q1. Why is ArrayList usually faster than LinkedList?¶
Because contiguous memory improves CPU cache locality and iteration speed.
Q2. Why specify an initial capacity for HashMap?¶
To reduce expensive resize and rehash operations.
Q3. Which collection uses the least memory?¶
Among common general-purpose collections, ArrayList is typically more memory-efficient than LinkedList because it does not allocate one node object per element.
Q4. Why is LinkedList rarely used?¶
Poor cache locality, higher memory overhead, and O(n) traversal often outweigh its theoretical insertion advantages.
Q5. What is the default load factor?¶
0.75
Q6. When should you use TreeMap?¶
When you need:
- Sorted keys
- Range queries (
headMap,tailMap,subMap) - Ordered traversal
Q7. Best collection for random access?¶
ArrayList
Q8. Best collection for lookups?¶
HashMap
average O(1).
Q9. Best concurrent map?¶
ConcurrentHashMap
Q10. Best way to benchmark collections?¶
Use JMH, not ad hoc timing loops.
Senior Interview Scenario¶
Question:
You need to load 5 million customer records into a HashMap.
What optimizations would you make?
Strong Answer:
- Estimate the required capacity based on the expected number of entries and load factor to minimize resizing.
- Keep the default load factor (
0.75) unless measurements indicate another value is beneficial. - Ensure keys implement efficient and well-distributed
hashCode()and consistentequals(). - Profile memory usage and GC behavior under realistic workloads.
- Benchmark with JMH if comparing implementation choices.
Key Takeaways¶
- Big-O alone is not enough; memory layout and cache locality matter.
ArrayListgenerally outperformsLinkedListfor most workloads.- Pre-sizing
HashMapcan significantly reduce resize costs. - The default load factor (
0.75) is a good balance for most applications. - Use
TreeMaponly when ordering is required. - Benchmark with JMH, not naive timing code.
- Collection selection should be driven by workload characteristics, not theoretical complexity alone.
Next: Part 14 — 100+ Senior Java Collections Interview Questions¶
This final part will cover:
- Conceptual questions
- Internal implementation questions
- JVM-related questions
- Coding questions
- Debugging scenarios
- Production troubleshooting
- Tricky interviewer questions with detailed answers
- FAANG/product-company style interview discussions