Escape Analysis in the JVM

Ondrej Kvasnovsky
3 min readJan 12, 2025

--

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:

  1. Reduced garbage collection pressure
  2. Better cache utilization with stack allocation
  3. 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

--

--

No responses yet