Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 372|回复: 0

[Java基础知识]尽可能使用堆栈变量

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-1 14:00:52 | 显示全部楼层 |阅读模式
    如果您频繁存取变量,就需要考虑从何处存取这些变量。变量是 static 变量,还是堆栈变量,或者是类的实例变量?变量的存储位置对存取它的代码的性能有明显的影响?例如,请考虑下面这段代码:

    class StackVars
    {
    private int instVar;
    private static int staticVar;

    //存取堆栈变量
    void stackAccess(int val)
    {
    int j=0;
    for (int i=0; i<val; i++)
    j += 1;
    }  
      
      
       //存取类的实例变量
    void instanceAccess(int val)
    {
    for (int i=0; i<val; i++)
    instVar += 1;
    }

    //存取类的 static 变量
    void staticAccess(int val)
    {
    for (int i=0; i<val; i++)
    staticVar += 1;
    }
    }
       这段代码中的每个方法都执行相同的循环,并反复相同的次数。唯一的不同是每个循环使一个不同类型的变量递增。方法 stackAccess 使一个局部堆栈变量递增,instanceAccess 使类的一个实例变量递增,而 staticAccess 使类的一个 static 变量递增。   instanceAccess 和 staticAccess 的执行时间基本相同。但是,stackAccess 要快两到三倍。存取堆栈变量如此快是因为,JVM 存取堆栈变量比它存取 static 变量或类的实例变量执行的操作少。请看一下为这三个方法生成的字节码:  
    Method void stackAccess(int)
    0 iconst_0 //将 0 压入堆栈。
    1 istore_2 //弹出 0 并将它存储在局部分变量表中索引为 2 的位置 (j)。
    2 iconst_0 //压入 0。
    3 istore_3 //弹出 0 并将它存储在局部变量表中索引为 3 的位置 (i)。
    4 goto 13 //跳至位置 13。
    7 iinc 2 1 //将存储在索引 2 处的 j 加 1。
    10 iinc 3 1 //将存储在索引 3 处的 i 加 1。
    13 iload_3 //压入索引 3 处的值 (i)。

    14 iload_1 //压入索引 1 处的值 (val)。
    15 if_icmplt 7 //弹出 i 和 val。如果 i 小于 val,则跳至位置 7。
    18 return //返回调用方法。

    Method void instanceAccess(int)
    0 iconst_0 //将 0 压入堆栈。
    1 istore_2 //弹出 0 并将它存储在局部变量表中索引为 2 的位置 (i)。
    2 goto 18 //跳至位置 18。
    5 aload_0 //压入索引 0 (this)。
    6 dup //复制堆栈顶的值并将它压入。
    7 getfield #19 <Field int instVar>
    //弹出 this 对象引用并压入 instVar 的值。
    10 iconst_1 //压入 1。
    11 iadd //弹出栈顶的两个值,并压入它们的和。
    12 putfield #19 <Field int instVar>
    //弹出栈顶的两个值并将和存储在 instVar 中。
    15 iinc 2 1 //将存储在索引 2 处的 i 加 1。
    18 iload_2 //压入索引 2 处的值 (i)。
    19 iload_1 //压入索引 1 处的值 (val)。
    20 if_icmplt 5 //弹出 i 和 val。如果 i 小于 val,则跳至位置 5。
    23 return //返回调用方法。


    Method void staticAccess(int)
    0 iconst_0 //将 0 压入堆栈。
    1 istore_2 //弹出 0 并将它存储在局部变量表中索引为 2 的位置 (i)。
    2 goto 16 //跳至位置 16。
    5 getstatic #25 <Field int staticVar>
    //将常数存储池中 staticVar 的值压入堆栈。
    8 iconst_1 //压入 1。
    9 iadd //弹出栈顶的两个值,并压入它们的和。
    10 putstatic #25 <Field int staticVar>
    //弹出和的值并将它存储在 staticVar 中。
    13 iinc 2 1 //将存储在索引 2 处的 i 加 1。
    16 iload_2 //压入索引 2 处的值 (i)。
    17 iload_1 //压入索引 1 处的值 (val)。
    18 if_icmplt 5 //弹出 i 和 val。如果 i 小于 val,则跳至位置 5。
    21 return //返回调用方法。
       查看字节码揭示了堆栈变量效率更高的原因。JVM 是一种基于堆栈的虚拟机,因此优化了对堆栈数据的存取和处理。所有局部变量都存储在一个局部变量表中,在 java 操作数堆栈中进行处理,并可被高效地存取。存取 static 变量和实例变量成本更高,因为 JVM 必须使用代价更高的操作码,并从常数存储池中存取它们。(常数存储池保存一个类型所使用的所有类型、字段和方法的符号引用。)   通常,在第一次从常数存储池中访问 static 变量或实例变量以后,JVM 将动态更改字节码以使用效率更高的操作码。尽管有这种优化,堆栈变量的存取仍然更快。   考虑到这些事实,就可以重新构建前面的代码,以便通过存取堆栈变量而不是实例变量或 static 变量使操作更高效。请考虑修改后的代码:  
    class StackVars
    {
    //与前面相同...
    void instanceAccess(int val)
    {
    int j = instVar;
    for (int i=0; i<val; i++)
    j += 1;
    instVar = j;
    }

    void staticAccess(int val)
    {
    int j = staticVar;
    for (int i=0; i<val; i++)
    j += 1;
    staticVar = j;
    }
    }
       方法 instanceAccess 和 staticAccess 被修改为将它们的实例变量或 static 变量复制到局部堆栈变量中。当变量的处理完成以后,其值又被复制回实例变量或 static 变量中。这种简单的更改明显提高了 instanceAccess 和 staticAccess 的性能。这三个方法的执行时间现在基本相同,instanceAccess 和 staticAccess 的执行速度只比 stackAccess 的执行速度慢大约 4%。   这并不表示您应该避免使用 static 变量或实例变量。您应该使用对您的设计有意义的存储机制。例如,如果您在一个循环中存取 static 变量或实例变量,则您可以临时将它们存储在一个局部堆栈变量中,这样就可以明显地提高代码的性能。这将提供最高效的字节码指令序列供 JVM 执行。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-5 02:32 , Processed in 0.381201 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表