Skip to content

# 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:

"HashMap lookup 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 LinkedList rarely 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.


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 consistent equals().
  • 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.
  • ArrayList generally outperforms LinkedList for most workloads.
  • Pre-sizing HashMap can significantly reduce resize costs.
  • The default load factor (0.75) is a good balance for most applications.
  • Use TreeMap only 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