Avoid Creating Unnecessary Objects
This item sounds simple, yet performance loss often starts here.
Classic Mistake: Redundant Allocation
String s = new String("Java Best Practices!"); // avoid
Better form:
String s = "Java Best Practices!";
What changes:
Inside a loop running one million iterations, the first version produces one million unused objects and extra GC pressure.
Hidden Cost: Autoboxing
Object creation hides behind syntax.
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
sum uses Long while i uses primitive long.
Each iteration triggers:
Result: billions of temporary objects under load.
Correct form:
long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
No boxing. No allocation. Stable throughput.
Example
Pricing engines loop through millions of cash flows.
Using Double instead of double inside valuation loops forces allocation on every step. GC pauses increase latency during market open. Primitive arithmetic keeps valuation pipelines stable under volume spikes.
Eliminate Obsolete Object References
Garbage collection does not prevent memory leaks.
Leak definition: objects stay reachable even though no logic needs them.
Common sources:
Example pattern:
private static final List<Order> ORDERS = new ArrayList<>();
Orders added during trading day remain reachable after settlement unless removed.
GC sees references. GC keeps memory.
Example
Order management systems accumulate millions of trade objects per session.
Without eviction, heap usage rises until latency spikes or OutOfMemoryError hits during peak execution windows.
Production outages follow, not due to math, but due to stale references.
Rules of Thumb
Takeaway
Performance issues start with allocation habits. GC removes unreachable memory, not unnecessary memory. Design and discipline decide which objects deserve space in the heap.