JVM的栈上分配

栏目: Java · 发布时间: 6年前

内容简介:栈上分配是JVM的一个优化选项。Java的对象一般都是分配在堆内存中的,而JVM开启了栈上分配后,允许把线程私有的对象(其它线程访问不到的对象)打散分配在栈上。这些分配在栈上的对象在方法调用结束后即自行销毁,不需要JVM触发垃圾回收器来回收,因此提升了JVM的性能。栈上分配在

栈上分配是JVM的一个优化选项。

Java的对象一般都是分配在堆内存中的,而JVM开启了栈上分配后,允许把线程私有的对象(其它线程访问不到的对象)打散分配在栈上。这些分配在栈上的对象在方法调用结束后即自行销毁,不需要JVM触发垃圾回收器来回收,因此提升了JVM的性能。

栈上分配在 JDK6u23 后默认是开启了的。下面通过代码来验证这一点。

验证

写一段代码:

public class OnStackTest {
    // User类
    public static class User{
        public int id=0;
        public String name="";
    }
    // 创建User类对象
    public static void alloc(){
        User u=new User();
        u.id=5;
        u.name="geym";
    }
    // 程序入口
    public static void main(String[] args) throws InterruptedException {
        long b=System.currentTimeMillis();
        // 创建大量的对象
        for(int i=0;i<99999999;i++){
            alloc();
        }
        long e=System.currentTimeMillis();
        // 打印执行时间
        System.out.println(e-b);
    }
}
复制代码

JDK6u22 环境下执行的结果:

-Xmx :指定最大堆内存

-Xms :指定最大堆内存

-XX:+PrintGC :打印GC日志, + 号表示启用, - 号表示禁用

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]
[GC 2336K->320K(5824K), 0.0026034 secs]
......
[GC 3280K->720K(6080K), 0.0001026 secs]
3304
复制代码

JDK6u23 环境下执行的结果:

D:\develop\jdk\6u23\bin\java.exe -Xmx5m -Xms5m -XX:+PrintGC geym.zbase.ch2.onstackalloc.OnStackTest
70
复制代码

从以上两个执行的结果可以看出,JDK6u22默认是没有开启栈上分配的,所以 alloc() 方法中new出来的User对象,是存放在堆上的。由于指定了最大堆内存只有5m,当堆内存不足就会触发GC。从JDK6u22的GC日志可以看出执行过程频繁触发GC,执行耗时3304,明显比JDK6u23的长。

而JDK6u23的执行过程中没有打印任何GC日志,证明这时候 alloc() 方法中new出来的User对象,是存放在 alloc() 方法对应的栈帧上的。当每一次执行 alloc() 方法,线程会向 Java 栈压入一个栈帧, new User() 创建的对象就存放在这个栈帧上; alloc() 方法执行结束,栈帧从Java栈弹出,user对象随栈帧的弹出销毁。

示意图:

JVM的栈上分配

相关JVM参数

JDK6u22及之前的版本 如果需要使用栈上分配来优化,可以加入以下参数:

java -server -Xmx5m -Xms5m -XX:+PrintGC -XX:+DoEscapeAnalysis -XX:-UseTLAB -XX:+EliminateAllocations  geym.zbase.ch2.onstackalloc.OnStackTest
复制代码

-XX:+DoEscapeAnalysis :开启逃逸分析

-XX:-UseTLAB :禁用TLAB(Thread Local Allocation Buffer)

-XX:+EliminateAllocations :开启标量替换

关于逃逸分析

逃逸分析的作用就是判断一个对象的作用域有没有可能逃出一个Java方法的作用域。请看下面例子演示:

// u对象逃出alloc的作用域,不符合栈上分配的条件
public class OnStackTest {
    private static User u;
    public static void alloc(){
        u=new User();
    }
}
复制代码
// u对象没有逃出alloc的作用域,符合栈上分配的条件
public class OnStackTest {
    public static void alloc(){
        User u=new User();
    }
}
复制代码

关于标量替换

启用标量替换后,允许把对象打散分配在栈上。 比如user对象有id和name属性,在启用标量替换后,user对象的id和name属性会视为局部变量分配在栈上

注意:逃逸分析和标量替换是栈上分配的前提,所以,在jvm参数中关闭了二者其中一个选项,栈上分配都不会生效。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Practical Algorithms for Programmers

Practical Algorithms for Programmers

Andrew Binstock、John Rex / Addison-Wesley Professional / 1995-06-29 / USD 39.99

Most algorithm books today are either academic textbooks or rehashes of the same tired set of algorithms. Practical Algorithms for Programmers is the first book to give complete code implementations o......一起来看看 《Practical Algorithms for Programmers》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具