mike-neckのブログ

Java or Groovy or Swift or Golang

JJUG ナイトセミナー 「Javaのプログラムはどうやって動いているの」に行ってきた #jjug

上記のとおりです。

jjug.doorkeeper.jp

ツイートが下記の通りまとめられています。

togetter.com

そのうちさくらばさんが資料をあげてくれると思います。

【2015/04/25 22:41 追記】さくらばさんが公開してくれました

JVM編の資料

www.slideshare.net

GC編の資料

www.slideshare.net


前半 JVMの話

javapを使ったことのある人が意外と少なかったです。まあ普段使うことないですね。

僕はバイトコードバイトコード言ってるけど実際どうなってるのという興味程度でつかったことがある程度です。

ちょうど家に帰ってから、また試しにやってみました。

public class Sample {
    private final int number;
    public Sample(int number) {
        this.number = number;
    }
    public int add(int other) {
        int result = number + other;
        return result;
    }
    public void print(String prefix) {
        System.out.println(prefix + number);
    }
}

このコードをjavacして、できたクラスファイルをjavap -c -l -v Sample.classとやるとこんなのが表示されます。

Classfile /C:/Users/mike/groovy/java/ReturnSample/Sample.class
  Last modified 2015/04/24; size 696 bytes
  MD5 checksum bfa4961178d1d535c570a22e45c348c8
  Compiled from "Sample.java"
public class Sample
  SourceFile: "Sample.java"
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #11.#24        //  java/lang/Object."<init>":()V
   #2 = Fieldref           #10.#25        //  Sample.number:I
   #3 = Fieldref           #26.#27        //  java/lang/System.out:Ljava/io/PrintStream;
   #4 = Class              #28            //  java/lang/StringBuilder
   #5 = Methodref          #4.#24         //  java/lang/StringBuilder."<init>":()V
   #6 = Methodref          #4.#29         //  java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #7 = Methodref          #4.#30         //  java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   #8 = Methodref          #4.#31         //  java/lang/StringBuilder.toString:()Ljava/lang/String;
   #9 = Methodref          #32.#33        //  java/io/PrintStream.println:(Ljava/lang/String;)V
  #10 = Class              #34            //  Sample
  #11 = Class              #35            //  java/lang/Object
  #12 = Utf8               number
  #13 = Utf8               I
  #14 = Utf8               <init>
  #15 = Utf8               (I)V
  #16 = Utf8               Code
  #17 = Utf8               LineNumberTable
  #18 = Utf8               add
  #19 = Utf8               (I)I
  #20 = Utf8               print
  #21 = Utf8               (Ljava/lang/String;)V
  #22 = Utf8               SourceFile
  #23 = Utf8               Sample.java
  #24 = NameAndType        #14:#36        //  "<init>":()V
  #25 = NameAndType        #12:#13        //  number:I
  #26 = Class              #37            //  java/lang/System
  #27 = NameAndType        #38:#39        //  out:Ljava/io/PrintStream;
  #28 = Utf8               java/lang/StringBuilder
  #29 = NameAndType        #40:#41        //  append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #30 = NameAndType        #40:#42        //  append:(I)Ljava/lang/StringBuilder;
  #31 = NameAndType        #43:#44        //  toString:()Ljava/lang/String;
  #32 = Class              #45            //  java/io/PrintStream
  #33 = NameAndType        #46:#21        //  println:(Ljava/lang/String;)V
  #34 = Utf8               Sample
  #35 = Utf8               java/lang/Object
  #36 = Utf8               ()V
  #37 = Utf8               java/lang/System
  #38 = Utf8               out
  #39 = Utf8               Ljava/io/PrintStream;
  #40 = Utf8               append
  #41 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #42 = Utf8               (I)Ljava/lang/StringBuilder;
  #43 = Utf8               toString
  #44 = Utf8               ()Ljava/lang/String;
  #45 = Utf8               java/io/PrintStream
  #46 = Utf8               println
{
  private final int number;
    descriptor: I
    flags: ACC_PRIVATE, ACC_FINAL


  public Sample(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iload_1
         6: putfield      #2                  // Field number:I
         9: return
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 5: 9

  public int add(int);
    descriptor: (I)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=2
         0: aload_0
         1: getfield      #2                  // Field number:I
         4: iload_1
         5: iadd
         6: istore_2
         7: iload_2
         8: ireturn
      LineNumberTable:
        line 7: 0
        line 8: 7

  public void print(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=2
         0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: new           #4                  // class java/lang/StringBuilder
         6: dup
         7: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
        10: aload_1
        11: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        14: aload_0
        15: getfield      #2                  // Field number:I
        18: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        21: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        24: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        27: return
      LineNumberTable:
        line 11: 0
        line 12: 27
}

あとは、これをThe Java Virtual Machine Specification, Java SE 8 Editionと照らしあわせて読んでいくだけです。

iload_1とかの1は引数、aloat_0thisのロードなどを表します。

では、まず簡単なaddメソッドに注目すると…

  public int add(int);
    descriptor: (I)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=2
         0: aload_0
         1: getfield      #2                  // Field number:I
         4: iload_1
         5: iadd
         6: istore_2
         7: iload_2
         8: ireturn
      LineNumberTable:
        line 7: 0
        line 8: 7

最初のaload_0でスタックは次のようになります。

stack
this

次のgetfield #2でスタックは次のようになります。

stack
this.number

次のiload_1でスタックは次のようになります。

stack
int(argument)
this.number

次のiaddでスタックは次のようになります。

stack
result(this.number + argument)

次のistore_2でスタックからlocal variableの2番地に値が移されます。

次のiload_2でlocal variableの2番地のデータがスタックに戻されます。

stack
result(this.number + argument)

最後のireturnでスタックの値が呼び出し元に返されます。


もちろん、これ僕の雑な理解なので、マサカリ大歓迎です。

javapをすると自然とThe Java Virtual Machine Specification, Java SE 8 Editionと仲良くなれるので、簡単なオブジェクトで構わないからやってみるといいかもしれません。


データ構造の話

ここで紹介されていたQueueとかDequeとか、Stackとか、LinkedListとかは自分で実装すると面白いので、是非実装するといいと思います。

スタックにこだわってた理由

カロンスタックを言いたいがためにマカロンがスライドのあちこちにありました。

マサカリたち

僕の前に座っていたおじさんが、声が小さいながら、各JVMベンダーとの互換性についてよい質問をしていました。

僕が知っている限りではecjでは通るけど、javacでは駄目なコードの例として、アノテーションの配列くらいでしょうか…まあ、コンパイルエラーしているコードを実行したらどうなるか、ちょっと不安がありますが…

takahashikzn.hatenablog.com

これは後で試してみたいけど、ecj使ったことないし、使い方わからん(´・ω・`)

後半 GCの話

これはJJUG CCC 2014 FallであったセッションConcurrent Mark-Sweep Garbage Collection 再入門の話とほとんど同じ話でした。

www.slideshare.net


以上、雑なまとめでした。


なお、僕の隣の島にすわったのがぜろゆ嬢でした。

なんか、残業たくさんしているけど、まだまだ生きていそうなので、元気のあるうちに残業ない所に行きま(無責任)

なお、ぜろゆ嬢が「定時退社したぜ!ドヤァ!」で両手の親指をあげて╭( ・ㅂ・)و ̑̑ グッ !ポーズして、ちょっと、こころがときめきました。

あ、おっさんの妄想ですので、気にしないでください(セクハラ)