Escape Analysis in the JVM
What is Escape Analysis?
Escape Analysis is a technique used by the JVM to determine the scope of object references. It analyzes whether objects are only used within a method (locally), within a thread, or escape to other threads/parts of the program. This analysis helps the JVM make optimization decisions about object allocation and synchronization.
Escape Analysis happens during the Just-In-Time (JIT) compilation phase, so it requires method to be “hot” enough.
Types of Object Escape
1. No escape (Method-Local)
Objects that are only used within the method where they’re created.
public class NoEscapeExample {
public int calculate() {
// StringBuilder only used in this method
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" World");
return sb.length();
}
}
2. Arguement escape
Objects that are passed as arguments but don’t escape beyond the called method.
public class ArgumentEscapeExample {
private void helper(StringBuilder sb) {
sb.append(" World");
}
public int process() {
StringBuilder sb = new StringBuilder("Hello");
helper(sb); // Argument escape, but still contained
return sb.length();
}
}
3. Global escape
Objects that escape to the heap and might be accessible from other threads.
public class GlobalEscapeExample {
private List<String> items = new ArrayList<>(); // Escapes to heap
public void add(String item) {
items.add(item); // Object accessible globally
}
}
Optimizations enabled by Escape Analysis
1. Stack allocation
When objects don’t escape a method, they can be allocated on the stack instead of the heap.
public class StackAllocationExample {
public double calculateDistance(int x1, int y1, int x2, int y2) {
// Point objects can be allocated on stack
Point p1 = new Point(x1, y1);
Point p2 = new Point(x2, y2);
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
}
}
2. Lock elision
Removing unnecessary synchronization when objects don’t escape thread scope.
public class LockElisionExample {
public int process() {
// StringBuffer is synchronized, but JVM can remove synchronization
StringBuffer sb = new StringBuffer();
sb.append("Hello");
sb.append(" World");
return sb.length();
}
}
3. Scalar replacement
Breaking down objects into their primitive components.
public class ScalarReplacementExample {
public int sumCoordinates() {
// Point can be broken down into x and y on stack
Point p = new Point(10, 20);
return p.x + p.y;
}
}
How to verify Escape Analysis
You can use JVM flags to control and verify escape analysis:
# Enable detailed escape analysis logging
java -XX:+PrintEscapeAnalysis YourProgram
# Disable escape analysis to compare performance
java -XX:-DoEscapeAnalysis YourProgram
The
PrintEscapeAnalysis
is available only in debug version of VM.
Common Patterns and Best Practices
1. Keep objects local whenpossible
// Good - object contained in method
public String formatName(String first, String last) {
StringBuilder sb = new StringBuilder();
sb.append(first).append(" ").append(last);
return sb.toString();
}
// Bad - object escapes unnecessarily
private StringBuilder sb = new StringBuilder();
public String formatName(String first, String last) {
sb.setLength(0);
sb.append(first).append(" ").append(last);
return sb.toString();
}
2. Avoid unnecessary object creation in loops
// Good - object can be optimized
public void processItems(List<String> items) {
for (String item : items) {
StringBuilder sb = new StringBuilder();
sb.append("Processing: ").append(item);
log(sb.toString());
}
}
// Bad - forced heap allocation
private StringBuilder sb = new StringBuilder();
public void processItems(List<String> items) {
for (String item : items) {
sb.setLength(0);
sb.append("Processing: ").append(item);
log(sb.toString());
}
}
Performance Impact
Escape Analysis can significantly impact performance:
- Reduced garbage collection pressure
- Better cache utilization with stack allocation
- Reduced synchronization overhead
However, it’s important to note that:
- Analysis itself takes CPU time
- Complex code patterns might prevent optimization
- Benefits vary depending on the specific application