Android開発を始めた時期と同じくして、Javaでの開発を開始しました。
それから、しばらくして聞いた「メンバ変数へのアクセスは遅い」が忘れられなかったので、試してみることにしました。
※ 別の方々も調査した結果を載せていらっしゃいますが、見ていないことにして、一から試してみました。

調査目標

Androidに搭載されているJavaVMでクラス変数(インスタンス間で共通の変数)、メンバ変数(インスタンス毎に領域が確保される変数)、スタック変数(メソッド内で一時的に宣言される変数)への読み書きの内、 速度にどの程度違いがあるか確認。ただし、絶対速度は条件が異なるため不問とする。
※ 調査目的はあくまで、読み書き速度の"相対比較"となります。

調査対象

調査対象としては以下のようになります。
  • JavaVM(Dalvik / ART)間で違いがあるか
  • 比較の対象として、クラス変数 / メンバ変数 / スタック変数のいずれが読み書きに時間が掛かるのか
  • 変数の型として、プリミティブ型のint / long / float / double、インスタンスとしてInteger / Long / Float / Doubleの合計8種類の間で読み書き速度に違いが発生するのか

調査条件

使用した端末やJavaバージョンなどの条件は以下のようになっています。
Dalvik向け ART向け
機種Xperia SOL23Nexus 6P
OSバージョン4.4.27.1.2
Javaバージョン1.8.0_131

調査方法

調査方法は以下のようになります。
  • 調査は公平にするため、android.os.AsyncTaskで起動したバックグラウンドスレッド上にて実施、且つ全ての調査を1バックグランウドスレッドにて実施
  • コンパイルによる最適化を防ぐために、以下のことを実施
    • 試験開始前に乱数を用意し、それを1,000,000回加算(読み書き)していく
    • 加算している期間の長さを算出する
    • 試験終了後にログに加算した結果を出力する
    • 念のため上記の1サイクルを10回繰り返し、そのときの平均値を比較する

調査結果

調査した際の読み書き時間(ミリ秒)は以下のようになりました。
※ 値が小さいほど読み書き速度が高速
  • Dalvik
  • クラス変数 メンバ変数 スタック変数
    int型5.2835.1132.004
    long型5.4824.9232.150
    float型9.4928.4311.837
    double型8.2728.4352.853
    Integer型4192.9124331.1494259.159
    Long型4541.0664341.7764604.080
    Float型4157.1234018.1804362.665
    Double型4514.4154461.2704581.336

  • ART
  • クラス変数 メンバ変数 スタック変数
    int型6.5065.3554.142
    long型6.2815.7293.975
    float型8.6438.1104.103
    double型8.8738.7584.646
    Integer型239.819243.297236.166
    Long型198.774195.686178.623
    Float型186.180186.019178.097
    Double型190.918181.656179.217
数値を見る限りは
  • プリミティブ型はスタック変数で読み書きする方が早い
  • ARTにおいてはInteger / Long / Float / Doubleのようなクラスインスタンスについてもスタック変数への読み書きが早い
  • 最も差が出たDalvik - Float型(メンバ変数 - スタック変数)で1読み書きあたり、344.485ナノ秒なので誤差に近い値になっている
となっている。Javaヒープへの読み書きが発生するInteger / Long /Float / Double型はJavaヒープへアクセスするための排他のためか全般的に速度劣化が激しかったですが、ARTにおいては、インスタンスのポインタをスタックに置くことで多少の改善は行えるようです。

傾向として、読み書き速度は
スタック変数 >> メンバ変数 >= クラス変数
ということで良いかと。

参考までに測定時に使用したAndroid Studioのプロジェクトはこちらを参照してください。

コメントの投稿