`

各种变量存储速度比较

阅读更多

先看下基础知识
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 与他联系

分享到:
评论

相关推荐

    Informatica调用存储过程图文流程

    * 提高数据集成速度:使用存储过程可以提高数据集成的速度,因为存储过程可以批量执行多个操作。 * 提高数据安全性:使用存储过程可以提高数据安全性,因为存储过程可以控制数据的访问权限。 * 提高数据可靠性:使用...

    DELPHI Variant变量的使用技巧

    一般说来,你可以用Variant 变量存储任何数据类型,对它执行各种操作和类型转换。需要注意的是:这违反了Pascal 语言的一贯原则,有悖于良好的编程习惯。variant 变量的类型检查和计算在运行期间才进行,编译器不会...

    oracle存储过程语法

    存储过程可以减少网络流量,提高数据库的响应速度,并且可以实现复杂的业务逻辑。 8. 存储过程的注意事项 * 存储过程参数不带取值范围。 * 变量带取值范围,后面接分号。 * 在判断语句前最好先用 `count(*)` 函数...

    oracle存储过程

    存储过程本身的执行速度非常快,而且,调用存储过程可以大大减少同数据库的交互次数。 第二、提高安全性。假如将SQL语句混合在ASP代码中,一旦代码失密,同时也就意味着库结构失密。 第三、有利于SQL语句的重用。...

    在C语言中如何存储并初始化成员变量

     通过以指针存储成员变量的方法化依赖  当成员变量的头文件非常大或者非常复杂;或者当你有大量的数据成员,并且不想减慢编译速度和强化相互依赖时。你会怎么做?简单来说就是将成员变量保存为指针形式,并用在类...

    js 数据存储和DOM编程

    由于局部变量处于作用域的起始位置,因此访问速度比访问跨域作用域变量(即除起始位置之外的外层作用域变量)更快。即变量处在作用域的位置越深,访问速度越慢。这也就说明,访问全局变量的速度是最慢的。 总的来说,...

    论文研究-一种简易变量施肥控制器的设计与实现 .pdf

    一种简易变量施肥控制器的设计与实现,赵改宾,司宾强,介绍了一种能根据测土配方施肥的控制器,该控制器以AT89C51为控制中心,通过读取存储在IC卡中的施肥量和对机具前进速度的实时检测,

    VGUS(用户图形界面设计工具)V4.3绿色免费版

    他可以将显示的字符、汉字等显示信息分别分配变量存储地址、定义显示格式,然后生成配置文件并下载到串口屏里。非常实用。 【软件特色】  1、256字节寄存器空间;  2、64K字(128K字节)变量存储器空间、8通道...

    EDA/PLD中的在C语言中如何存储并初始化成员变量

     通过以指针存储成员变量的方法最小化依赖  当成员变量的头文件非常大或者非常复杂;或者当你有大量的数据成员,并且不想减慢编译速度和强化相互依赖时。你会怎么做?简单来说就是将成员变量保存为指针形式,并用...

    嵌入式系统/ARM技术中的简述嵌入式系统的高速度大容量非易失随机数据存储

     高速度、大容量、非易失、随机存储是现代嵌入式应用体系数据存储的迫切需要,特别是大量的测/控过程参变量、音/视频数据、高速通信数据包、可变配置文件等的存储。高速度是指存取访问速度快,对于并行接口存储器为...

    21.RAM_SD.rar--RAM产生数据,进入SD卡存储,SPI模式按片存储

    在RAM中循环产生0~Z的数据,产生数据都是速度由变量rate控制,RAM写满时写入SD卡存储起来,一次写入一个block。程序主要采用了有有限状态机和verilog行为级描述,组合电路与时序电路严格分开,注释较为清楚。

    C语言程序设计标准教程

    在形参表中给出的参数称为形式参数, 它们可以是各种类型的变量, 各参数之间用逗号间隔。在进行函数调用时,主调函数将赋予这些形式参数实际的值。 形参既然是变量,当然必须给以类型说明。例如,定义一个函数, ...

    计算机 c++程序设计语言考试附带答案 本文链接:https://blog.csdn.net/Candy5204/article

    (2) register 称为寄存器型,使用register 关键词说明的变量主要目的是想将所说明的变量放入CPU 的寄存器存储空间中,这样可以加快程序的运行速度。(3) static 称为静态存储类型, 在C++ 语言中, 既可以在函数体内...

    内存对齐问题的完美解释.doc

    为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐...

    病态线性方程组的求解的源代码及运行结果截图

    在符号名说明中,我们定义了多个变量,包括用于存储第 k+1 次和第 k 次迭代结果的差值的绝对值的变量 c,用于存储第 k+1 次迭代结果的变量 x,用于存储初始向量的变量 x0,用于存储第 k+1 次和第 k 次迭代结果的差值...

    S7-1200 与S7-1500 中优化的 DB 块和标准 DB 块有哪些区别.docx

     以符号寻址,编程者无需考虑 DB 块中每个变量存储的具体地址,每个变量在 CPU 中存储的位置由 PLC 的系统自动进行分配。  CPU 与 HMI (如 Panel)连接时,由于优化的 DB 是靠符号寻址,所以当 PLC 变量连接到...

    java 把大文件分割为小文件

    Java 将大文件分割为小文件 Java 将大文件分割为小文件是指将一个大文件分割成多个小文件,以便于存储、管理和处理。下面是实现该功能的 Java 代码...在上面的代码中,使用了 sqlitFilePath 变量来存储文件写入路径。

    DNAC-TEMPLATES:DNA Center中使用速度脚本,变量和复合方法的模板示例

    该存储库将包含脚本和示例,其中包含以下内容: 速度脚本变数绑定变量复合模板该存储库的目的是提供实用指南,以使工程师能够快速开始使用DNAC自动化并开始转换IOS CLI模板。 他们多年来一直在使用模板,并且具有...

    实现JavaScript高性能的数据存储

    一般来说:[字面量,局部变量]运行速度&gt;[数组,对象成员] 2.内部属性包含了一个函数被创建的作用域中对象的集合。这个集合被称为作用域链。 3.执行函数-&gt;创建执行环境-&gt;创建活动对象(即函数运行时变量对象)。 所以多次...

Global site tag (gtag.js) - Google Analytics