<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Sung in Blog

               一些技術文章 & 一些生活雜碎
    如果您頻繁存取變量,就需要考慮從何處存取這些變量。變量是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 執行。
    posted on 2005-11-04 15:03 Sung 閱讀(294) 評論(0)  編輯  收藏 所屬分類: Java
    主站蜘蛛池模板: 亚洲av无码成人精品区一本二本| 亚洲一区二区三区日本久久九| 亚洲午夜无码久久久久小说 | 永久免费AV无码国产网站| 亚洲综合无码一区二区| 色欲色香天天天综合网站免费| 久久被窝电影亚洲爽爽爽| 久久福利青草精品资源站免费| 国产亚洲综合一区二区三区| 成人免费毛片视频| 欧美亚洲精品一区二区| 又爽又黄无遮挡高清免费视频 | 亚洲成av人在片观看| 国产免费久久精品99久久| 亚洲小说区图片区另类春色| 免费看少妇高潮成人片| 亚洲欧洲国产精品你懂的| 精品无码免费专区毛片| 亚洲熟妇av午夜无码不卡| 免费人成在线观看网站视频| 精品久久久久久国产免费了| 久久亚洲精品国产精品黑人| 91免费人成网站在线观看18| 亚洲日本在线电影| 久久久久亚洲爆乳少妇无| 香蕉免费一区二区三区| 亚洲自国产拍揄拍| 久9这里精品免费视频| 亚洲另类小说图片| 国产hs免费高清在线观看| 中文字幕免费在线看线人动作大片| 亚洲国产成人久久精品动漫| 午夜神器成在线人成在线人免费| 猫咪免费人成网站在线观看入口| 亚洲国产精品无码久久久不卡| 岛国av无码免费无禁网站| 国产精品午夜免费观看网站| 亚洲最大在线视频| 亚洲国产专区一区| 日本免费xxxx| 中文字幕免费视频精品一|