`

各种变量存储速度比较

阅读更多

先看下基础知识
public class Variable{

     static int allClicks=0;//类变量

     String str="hello world";//实例变量\个人认为 当创建实例时 初始化之前进行初始化赋值!然后初始化如果有明文赋值,进行赋值!!

     public void method(){

        int i =0;//局部变量

     }

}

如果您频繁存取变量,就需要考虑从何处存取这些变量。变量是 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 执行。




关于作者



  Peter Haggar 是 IBM 的高级软件工程师。他目前正在研究新兴的 Java 和因特网技术,并且是 IBM 实时 Java 参考实现的项目主持人。他有丰富的编程经验,从事过开发工具、类库和操作系统等方面的工作。在许多行业研讨会上,他也经常就 Java 和其他技术作技术性发言。他于 1987 年在纽约获得 Clarkson 大学计算机科学学士学位。可以通过 haggar@us.ibm.com 与他联系

分享到:
评论

相关推荐

    变量的存储方式

    - 寄存器变量(`register`关键字):这是一种优化策略,尝试将变量存储在CPU的寄存器中,以提高访问速度。但实际是否能存储在寄存器取决于编译器和可用资源,如果无法满足,编译器会自动降级为自动变量存储。 3. ...

    C++基础--变量的作用域和存储区

    寄存器变量试图将变量存储在CPU的寄存器中,以提高访问速度。然而,实际是否存储在寄存器取决于编译器和可用的寄存器资源,编译器可能会选择将其放在内存中。 除了局部和全局作用域,还有两种特殊的作用域:文件...

    C++变量总结 说明各种变量

    寄存器变量是一种特殊的优化手段,试图将变量存储在CPU的寄存器中以提高速度,但实际是否存储在寄存器由编译器决定。 变量的生存期指的是变量值保留的期限。静态存储变量的生存期贯穿整个程序执行过程,而动态存储...

    变量的存储小结

    综上所述,了解和掌握C语言中的变量存储类、类型、存在期和作用域,对于编写高效、可靠的程序至关重要。这不仅仅涉及简单的语法知识,还关系到内存管理、程序设计思想以及代码的可维护性。对于初学者而言,通过理解...

    变量的存储类型.zip

    4. **注册变量(Register Variables)**:这是一种优化措施,请求编译器尽可能将变量存储在CPU寄存器中,以提高访问速度。但编译器并不保证满足这个请求,实际存储位置取决于编译器和可用资源。 5. **外部变量...

    变量的存储域(通过linux下size命令分析).pdf

    在计算机编程中,尤其是使用C语言时,理解变量的存储域是至关重要的。...理解这些内存区域的划分和变量存储规则对于编写高效、无内存泄漏的代码至关重要,尤其是在资源有限的嵌入式系统或者需要优化性能的场合。

    局部变量 全局变量和存储分类 局部变量作用域和生存期PPT学习教案.pptx

    `register`类型试图将变量存储在CPU寄存器中以提高速度,但实际能否实现取决于可用寄存器的数量。`static`类型的变量具有静态存储,无论函数是否被调用,它们的值都会保留。如果在函数内部定义,`static`变量的作用...

    kuka系统变量的变量最新版中文版

    首先,KUKA C4 系统变量是 KUKA 机器人控制系统中的一个重要概念,它们是用来存储和管理机器人运行状态、参数和功能的数据结构。这些变量可以分为不同类型,如位置、速度、力矩、传感器数据等,为编程提供了极大的...

    计算机机密-变量的存储【精】

    ### 计算机机密——变量的存储精解 #### 数据存放原理与实践 计算机程序在运行过程中,根据数据的不同用途和生命周期,将其存放在内存的不同区域,这一过程被称为数据的存储管理。根据给定文件的描述,我们可以...

    ABB机器人中变量的3种存储类型使用时的区别.docx

    本文将深入探讨ABB机器人中三种主要的变量存储类型:VAR、PERS和CONST,以及它们在使用时的区别。 首先,我们来看CONST常量。CONST变量,顾名思义,它的值在程序的整个生命周期内是不可变的。这意味着一旦在声明时...

    如何查看或修改FANUC机器人的系统变量?.docx

    它们是机器人控制器内部存储的关键数据,用于管理机器人的运行状态、参数设置以及各种功能。了解和正确使用系统变量是提升工作效率和保证机器人运行稳定的关键。下面将详细阐述如何查看和修改FANUC机器人的系统变量...

    发那科机器人系统变量清单(全集)

    发那科机器人系统变量清单是FANUC机器人编程与维护中的一个重要组成部分,它包含了机器人的各种内部状态和配置信息。这些系统变量对于理解和诊断机器人系统的运行情况至关重要,尤其在出现问题时,服务人员会通过...

    zynq修改uboot环境变量保存到sd卡.docx

    在Block Design中,确保网络接口的速率设置为100Mbps或1000Mbps,这主要影响网络连接的速度,但对保存环境变量到SD卡的过程没有直接影响。 接下来,通过Petalinux工具生成设备树源文件(Device Tree Source, DTS)...

    如何合理设置C语言变量.pdf

    "C语言变量存储类型和数据类型分析" 本文将从C语言变量的存储类型和数据类型的角度出发,对C语言变量的五种存储类型(auto、register、static、extern、const)进行详细分析,并探讨如何合理设置C语言变量的存储...

    KUKA机器人系统变量手册.rar

    系统变量在KUKA机器人中起着核心作用,它们是机器人控制系统中的关键参数,用来存储和控制机器人的各种状态和功能。 系统变量可以分为不同类别,包括位置数据、速度、力矩、状态信息、系统配置参数等。例如,位置...

    局部变量、全局变量、堆、堆栈、静态和全局

    栈区的管理由系统自动完成,速度快但空间有限,通常适用于短期、小规模的数据存储。 全局变量则在整个程序中都可以访问,从程序开始到结束都存在于内存中,存放在数据区。全局变量在程序的生命周期内只初始化一次,...

    KUKA系统软件-系统变量表.pdf

    每种类别的变量都有其特定的用途和使用方式,例如数字变量常用于存储数值信息,字符串变量用于存储文本信息,布尔变量则用于处理逻辑上的真(true)或假(false)情况。 除了分类介绍外,文档还提供了系统变量的...

    Keil c51指针变量

    - **Xdata区**:适合不经常使用或者对速度要求不高的变量。 - **Large模式**:可以节省data区的空间,将未定义内存位置的变量放在xdata区。 - **指针变量**:明确指明指针的指向类型,可以减少内存消耗。 #### 五、...

    FANUC机器人系统变量详细说明解释1(英文版).pdf

    系统变量是FANUC机器人控制系统中的一个重要部分,它们可以被编程使用来存储和管理机器人控制器的配置信息和运行状态。系统变量的功能包括但不限于控制机器人的运动参数、处理输入输出信号以及监控机器人的工作状态...

Global site tag (gtag.js) - Google Analytics