網站建設| 數據庫類| 圖形圖象| 程序設計| 現代辦公| 操作系統| 考試認證| 網絡技術| 軟件工程| 電腦相關| 文學作品
網站開發| 網頁制作| 操作系統| 圖象圖形| 考試認證| 數據庫類| 程序設計| 硬件技術| 現代辦公| 網絡技術| 笑話頻道
 
您的位置: 電腦書庫首頁-> 電腦文摘-> 網頁制作-> HTML-> JAVA經驗談:盡可能使用堆棧變量

JAVA經驗談:盡可能使用堆棧變量
作者:chensheng913 來源:CSDN 加入時間:2004-12-4
相關文章 相關書籍:
    如果您頻繁存取變量,就需要考慮從何處存取這些變量。變量是 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 執行。


[文章錄入員:迷茫森林]

相關文章 相關書籍:
本站推薦內容

近期主機類熱搜關鍵詞:
美國服務器 美國服務器租用 海外服務器租用 國外服務器租用

HTML
DreamWeaver
FrontPage
FireWorks
Flash
HTML
其它
電腦教程閱讀排行
·顯示你個性的鼠標指針
·HTML 語法
·如何利用ASP把圖片上傳到數據庫...
·VBScript教程(一)
·JavaScript[對象.屬性...
·JavaScript 小技巧全集...
·VBScript教程(二)
·CSS樣式表高效使用的技巧
·VBScript教程(三)
·多種網頁彈出窗口代碼
山东11选5