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.