On-stack allocation is an optimization option for the JVM.

Java objects are typically allocated in heap memory, but when the JVM turns on stack allocation, it allows objects that are private to a thread (objects that are not accessible to other threads) to be broken up and allocated on the stack. These objects allocated on the stack are destroyed upon completion of the method call without the JVM triggering the garbage collector to collect them, thus improving JVM performance.

Stack allocation is enabled by default in JDK6u23. Let’s verify this with code.

validation

Write a piece of code:

public class OnStackTest {
    / / the User class
    public static class User{
        public int id=0;
        public String name="";
    }
    // Create a User object
    public static void alloc(a){
        User u=new User();
        u.id=5;
        u.name="geym";
    }
    // Program entry
    public static void main(String[] args) throws InterruptedException {
        long b=System.currentTimeMillis();
        // Create lots of objects
        for(int i=0; i<99999999; i++){ alloc(); }long e=System.currentTimeMillis();
        // Prints the execution timeSystem.out.println(e-b); }}Copy the code

Results of execution in JDK6u22:

D:\develop\jdk\6u22\bin\java.exe -Xmx5m -Xms5m -XX:+PrintGC geym.zbase.ch2.onstackalloc.OnStackTest [GC 2048K->288K(5824K), 0.0049399 secs [GC 2336K->288K(5824K), 0.0013872 secs] 0.0026034 secs]... [GC 3280K->720K(6080K), 0.0001026 secs] 3304Copy the code

The meanings of the above parameters:

-xmx: specifies the maximum heap memory. -xms: specifies the maximum heap memory. -xx :+PrintGC: prints GC logs

Results of execution in JDK6u23:

D:\develop\jdk\6u23\bin\java.exe -Xmx5m -Xms5m -XX:+PrintGC geym.zbase.ch2.onstackalloc.OnStackTest
70
Copy the code

As you can see from the above two execution results, the stack allocation is not enabled by default in JDK6u22, so the new User object in the alloc() method is stored on the heap. Since the maximum heap memory specified is only 5m, GC is triggered when the heap is out of memory. The GC log of JDK6u22 shows that GC is frequently triggered and the execution time is 3304, which is significantly longer than that of JDK6u23.

The alloc() User object is stored on the corresponding stack frame of the alloc() method. Each time the alloc() method is executed, the thread pushes a stack frame onto the Java stack, where the object created by new User() is stored. The alloc() method completes, the stack frame pops out of the Java stack, and the User object is destroyed along with the stack frame.

Schematic diagram:

Related JVM parameters

In JDK6u22 and earlier, if you need to use stack allocation to optimize, you can add the following parameters:

java -server -Xmx5m -Xms5m -XX:+PrintGC -XX:+DoEscapeAnalysis -XX:-UseTLAB -XX:+EliminateAllocations  geym.zbase.ch2.onstackalloc.OnStackTest
Copy the code

-xx :+DoEscapeAnalysis: Enables escape analysis

-xx: -usetlab: Disables TLAB (Thread Local Allocation Buffer)

-xx :+EliminateAllocations: Enables scalar substitutions

About Escape analysis

The purpose of escape analysis is to determine whether an object is likely to escape the scope of a Java method. Take a look at the following example:

Public class OnStackTest {private static User u; private static User u; public static voidalloc(){ u=new User(); }}Copy the code
Public class OnStackTest {public static voidalloc(){ User u=new User(); }}Copy the code

On scalar substitution

With scalar substitution enabled, objects are allowed to be broken up and distributed on the stack. For example, the USER object has id and name attributes. After scalar substitution is enabled, the ID and name attributes of the User object are allocated on the stack as local variables

Note: Escape analysis and scalar replacement are prerequisites for on-stack allocation, so if either option is turned off in the JVM parameter, on-stack allocation does not take effect.