各種変数記憶速度比較


まず基礎知識を見てみましょう
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は2~3倍速い.アクセススタック変数がこのように速いのは、JVMアクセススタック変数がstatic変数またはクラスのインスタンス変数にアクセスするよりも実行される操作が少ないためです.この3つの方法で生成されたバイトコードを見てください.
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がよりコストの高いオペレーティングコードを使用し、定数ストレージプールからアクセスする必要があるため、よりコストがかかります.(定数ストレージプールは、1つのタイプで使用されるすべてのタイプ、フィールド、およびメソッドのシンボル参照を保存します.)
通常、JVMは、定数ストレージプールからstatic変数またはインスタンス変数に初めてアクセスした後、より効率的なオペレーティングコードを使用するためにバイトコードを動的に変更します.この最適化にもかかわらず、スタック変数のアクセスは高速です.
これらの事実を考慮すると、インスタンス変数や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のパフォーマンスが大幅に向上します.この3つの方法の実行時間はほぼ同じであり、instanceAccessとstaticAccessの実行速度はstackAccessの実行速度より約4%遅いだけである.
これは、static変数またはインスタンス変数の使用を避けるべきではありません.設計に意味のあるストレージメカニズムを使用する必要があります.たとえば、static変数またはインスタンス変数に1サイクルでアクセスすると、ローカルスタック変数に一時的に格納できます.これにより、コードのパフォーマンスが大幅に向上します.これにより、JVMが実行するために最も効率的なバイトコード命令シーケンスが提供される.
作者について
  Peter HaggarはIBMの高級ソフトウェアエンジニアです.彼は現在、新興のJavaとインターネット技術を研究しており、IBMのリアルタイムJavaリファレンス実装のプロジェクト司会者である.彼はプログラミングの経験が豊富で、開発ツール、クラスライブラリ、オペレーティングシステムなどの仕事をしたことがあります.多くの業界のシンポジウムでは、Javaや他の技術について技術的な発言をすることもよくあります.彼は1987年にニューヨークでClarkson大学コンピュータ科学学士号を取得した.に合格[email protected]彼に連絡する