インスタンス変数へのアクセスより、ローカル変数へアクセス
private Model model; public void updateModel() { Model m = this.model; // 更新処理 }
今日、上のようなコードを書いてたら、同僚から「なんでこんなことしてるんですか?」と聞かれたので。
インスタンス変数にアクセスするより、ローカル変数に代入してアクセスした方がパフォーマンス上がるらしいですよ。確か、ローカル変数はスタックに積まれて、インスタンス変数はヒープにありそうで、その辺の違いっすかねーと、濁してきた。
どっかの本で見た気がするんだけど思い出せない。ぐぐってみるとIBMのサイトにそれっぽいのがあった。
http://www.ibm.com/developerworks/jp/java/library/j-praxis/pr35.html
てか、上のコードでもパフォーマンス違うのかなーと思い、テスト。
class Test { private Model model = new Model(); public static void main(String args[]) { Test t = new Test(); t.updateInstanceModel(); t.updateLocalModel(); } // インスタンス変数に直接アクセス public void updateInstanceModel() { long start = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { model.id = 10; model.name = "jhon"; } long end = System.currentTimeMillis(); System.out.println("updateInstanceModel: " + (end - start)); } // ローカル変数へからのアクセス public void updateLocalModel() { Model m = this.model; long start = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { m.id = 10; m.name = "jhon"; } long end = System.currentTimeMillis(); System.out.println("updateLocalModel: " + (end - start)); } }
TestクラスからアクセスされるModelクラス
class Model { public int id; public String name; }
javapコマンドで逆アセンブル
a$ javap -c Test Compiled from "Test.java" class Test extends java.lang.Object{ Test(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: aload_0 5: new #2; //class Model 8: dup 9: invokespecial #3; //Method Model."<init>":()V 12: putfield #4; //Field model:LModel; 15: return public static void main(java.lang.String[]); Code: 0: new #5; //class Test 3: dup 4: invokespecial #6; //Method "<init>":()V 7: astore_1 8: aload_1 9: invokevirtual #7; //Method updateInstanceModel:()V 12: aload_1 13: invokevirtual #8; //Method updateLocalModel:()V 16: return public void updateInstanceModel(); Code: 0: invokestatic #9; //Method java/lang/System.currentTimeMillis:()J 3: lstore_1 4: iconst_0 5: istore_3 6: iload_3 7: ldc #10; //int 1000000000 9: if_icmpge 36 12: aload_0 13: getfield #4; //Field model:LModel; 16: bipush 10 18: putfield #11; //Field Model.id:I 21: aload_0 22: getfield #4; //Field model:LModel; 25: ldc #12; //String jhon 27: putfield #13; //Field Model.name:Ljava/lang/String; 30: iinc 3, 1 33: goto 6 36: invokestatic #9; //Method java/lang/System.currentTimeMillis:()J 39: lstore_3 40: getstatic #14; //Field java/lang/System.out:Ljava/io/PrintStream; 43: new #15; //class java/lang/StringBuilder 46: dup 47: invokespecial #16; //Method java/lang/StringBuilder."<init>":()V 50: ldc #17; //String updateInstanceModel: 52: invokevirtual #18; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 55: lload_3 56: lload_1 57: lsub 58: invokevirtual #19; //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder; 61: invokevirtual #20; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 64: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 67: return public void updateLocalModel(); Code: 0: aload_0 1: getfield #4; //Field model:LModel; 4: astore_1 5: invokestatic #9; //Method java/lang/System.currentTimeMillis:()J 8: lstore_2 9: iconst_0 10: istore 4 12: iload 4 14: ldc #10; //int 1000000000 16: if_icmpge 37 19: aload_1 20: bipush 10 22: putfield #11; //Field Model.id:I 25: aload_1 26: ldc #12; //String jhon 28: putfield #13; //Field Model.name:Ljava/lang/String; 31: iinc 4, 1 34: goto 12 37: invokestatic #9; //Method java/lang/System.currentTimeMillis:()J 40: lstore 4 42: getstatic #14; //Field java/lang/System.out:Ljava/io/PrintStream; 45: new #15; //class java/lang/StringBuilder 48: dup 49: invokespecial #16; //Method java/lang/StringBuilder."<init>":()V 52: ldc #22; //String updateLocalModel: 54: invokevirtual #18; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 57: lload 4 59: lload_2 60: lsub 61: invokevirtual #19; //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder; 64: invokevirtual #20; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 67: invokevirtual #21; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 70: return }
うーん。何か違うが、実際はどうなのかというと。何回か実行して処理時間の差をとってみた。こんな計測じゃ微妙かもしれんが。。
1回目 updateInstanceModel: 4856 updateLocalModel: 3640 2回目 updateInstanceModel: 4564 updateLocalModel: 3922 3回目 updateInstanceModel: 4747 updateLocalModel: 3541 4回目 updateInstanceModel: 5068 updateLocalModel: 3621 5回目 updateInstanceModel: 4704 updateLocalModel: 3615
お、ローカル変数に入れたら早いっぽい。(てか、そこまで気をつかう程の差は出てない気がするけどそれは言わない約束)
とここまでやったのはいいけど、逆アセンブルしたコードが読めない;;ま、とりあえず今日はこの辺で。(結局納得してもらえる説明はできそうにない。。)