実行時のメモリ構造(2) Javaスタック内動作他

Slides:



Advertisements
Similar presentations
独習JAVA Chapter 6 6.6 クラスの修飾子 6.7 変数の修飾子 結城 隆. 6.6 クラスの修飾 abstract インスタンス化できないクラス。1つまたは複数のサブクラスで 実装してはじめてインスタンス化できる。 final 継承されたくないことを明示する。これ以上機能拡張 / 変更でき.
Advertisements

1 Reference, 配列,アクセスフラ グ, jdb での観察, アセンブラ上での編集 2002 年 6 月 6 日 海谷 治彦.
6.4継承とメソッド 6.5継承とコンストラクタ 11月28日 時田 陽一
プログラミング演習II 2004年11月 30日(第6回) 理学部数学科・木村巌.
クラスファイルの構造解析(1) 2002年6月16日 2003年6月8日 改訂 海谷 治彦.
~手続き指向からオブジェクト指向へ(Ⅰ)~
アルゴリズムとデータ構造1 2007年6月12日
アルゴリズムとプログラミング (Algorithms and Programming)
実行時のメモリ構造(1) Jasminの基礎とフレーム内動作
Javaのインタフェース についての補足 2006年5月17日 海谷 治彦.
第2回:Javaの変数と型の宣言 プログラミングII 2007年10月2日.
アルゴリズムとプログラミング (Algorithms and Programming)
Java2セキュリティ, クラスローダー,ベリファイア
例外,並行・同期処理,ゴミ集め 2002年7月7日 海谷 治彦.
第2章 Eclipseと簡単なオブジェクト 指向プログラミング
第20章 Flyweight ~同じものを共有して無駄をなくす~
オブジェクト指向入門.
計算機プログラミングI 第8回 2002年12月5日(木) メソッドとクラス (教科書6章) クイズ インスタンスメソッド インスタンス変数
RMI ソフトウェア特論 第6回 /
第6回独習Javaゼミ 第6章 セクション4~6 発表者 直江 宗紀.
進捗 Javaバイトコード変換による 細粒度CPU資源管理
コンパイラの解析 (2) GCJのデータ構造 - 1.
~手続き指向からオブジェクト指向へ[Ⅱ]~
細かい粒度でコードの再利用を可能とするメソッド内メソッドのJava言語への導入
8.1 例外処理 8.2 catchブロックの検索 8.3 throwステートメント 8.4 例外とエラークラス 8.6 独自の例外
変数のスコープ クラス クラス変数 すべてのメソッドの外側でstaticで定義
プログラミング言語入門 手続き型言語としてのJava
JAVA入門後期⑩ 情報処理試験例題解説.
アルゴリズムとプログラミング (Algorithms and Programming)
細かい粒度で コードの再利用を可能とする メソッド内メソッドと その効率の良い実装方法の提案
第9章 例外処理,パッケージ 9.1 例外処理 9.2 ガーベッジコレクション.
オブジェクト指向 プログラミング 第八回 知能情報学部 新田直也.
独習JAVA 6.8 コンストラクタの修飾子 6.9 メソッドの修飾子 6.10 ObjectクラスとClassクラス 11月28日(金)
第7回独習Javaゼミ セクション 1~4 発表者 直江 宗紀.
オブジェクト指向 プログラミング 第十三回 知能情報学部 新田直也.
リファレンスの復習と例外処理 2005年6月14日 海谷 治彦.
リファレンス,配列,例外処理 その他演習に役立つこと
コンパイラの解析 (3) クラスとインスタンスの初期化.
ローカル変数とグローバル変数 ローカル変数  定義された関数内だけで使用できる変数 グローバル変数 プログラム全体で使用できる変数.
第11週:super/subクラス、継承性、メソッド再定義
Integer Java Virtual Machine
Java Bytecode Modification and Applet Security
クラスファイルの構造解析(2) 2003年6月23日 海谷 治彦.
プログラミング言語論 第五回 理工学部 情報システム工学科 新田直也.
Java8について 2014/03/07.
パッケージ,アクセス修飾子 2008年4月27日 海谷 治彦.
アルゴリズムとデータ構造 2010年7月26日
オブジェクト指向プログラミングと開発環境
new Calc(7,3).divInt()実行前
オブジェクト・プログラミング 第8回.
JAVAバイトコードにおける データ依存解析手法の提案と実装
アルゴリズムとプログラミング (Algorithms and Programming)
オブジェクト指向 プログラミング 第九回 知能情報学部 新田直也.
オブジェクト指向 プログラミング 第八回 知能情報学部 新田直也.
プログラミング言語論 第十一回 理工学部 情報システム工学科 新田直也.
プログラムが実行されるまで 2002年4月14日 海谷 治彦.
計算機プログラミングI 木曜日 1時限・5時限 担当: 増原英彦 第1回 2002年10月10日(木)
計算機プログラミングI 第3回 プリミティブ値 クラスメソッド クラス変数 式と演算 変数の利用
アルゴリズムとデータ構造1 2008年7月24日
Javaスタック ヒープ (インスタンス置き場) <init> i1215 i1512 r= r= | locals | =4
Chapter 5 5.5 thisキーワード 5.6 インスタンス変数とインスタンスメソッド 結城 隆
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
JAVA入門⑥ クラスとインスタンス.
オブジェクト指向言語論 第九回 知能情報学部 新田直也.
フレンド関数とフレンド演算子.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
値渡しと参照渡しについて.
オブジェクト指向言語論 第九回 知能情報学部 新田直也.
計算機プログラミングI 第2回 2002年10月17日(木) 履習登録 複習 ライブラリの利用 (2.6-7) 式・値・代入 (2.6-8)
計算機プログラミングI 第10回 2002年12月19日(木) メソッドの再定義と動的結合 クイズ メソッドの再定義 (オーバーライド)
Presentation transcript:

実行時のメモリ構造(2) Javaスタック内動作他 2002年5月27日 海谷 治彦

JVM内の基本構造(大雑把) クラスファイルの 内容チェック クラスデータを保存 クラス ファイル クラスローダー メソッドエリア 実行 エンジン ヒープエリア ヒープエリア ヒープエリア Javaスタック ヒープ 各実行スレッドのローカルデータ(実行経過)を保存 インスタンスデータを保存 教科書 p.15 * 原著および教科書p.15をベースに書いた. リンク有

Javaスタック内の構造 フレーム フレーム フレーム 「フレーム」という要素のスタック. フレームは,1回のメソッド呼び出しに対応. オペランド スタック ローカル 変数 フレーム オペランド スタック ローカル 変数 フレーム オペランド スタック ローカル 変数 フレーム プログラム カウンタ スタック増減 「フレーム」という要素のスタック. フレームは,1回のメソッド呼び出しに対応. フレーム内の計算のためにも,スタック(オペランドスタック)が利用されている. 詳細は「実行時の構造」の回にて. 例えば教科書 p.20の図

本日のお題 Javaスタック内のフレームの増減を理解 インスタンス変数の扱い 静的メソッド,変数について コンストラクタについて メソッド(関数)呼び出しの繰り返しによる計算機構の復習(or 理解). インスタンス変数の扱い 情報隠蔽の実際 静的メソッド,変数について コンストラクタについて

例題: 簡単な計算クラス calc/Calc.java public class Calc{ int val(int v){return v;} int add(int a, int b){return a+b; } int sub(int a, int b){ return a-b;} int mul(int a, int b){return a*b;} public static void main(String[] args){ Calc c=new Calc(); int a=c.mul(c.val(2), c.add(c.val(3), c.val(4))); // 2*(3+4) System.out.println(a); }

関数呼び出しの構造 calc/Calc.java a=c.mul(c.val(2), c.add(c.val(3), c.val(4)));

逆ポーランドによる展開 calc/Calc.java .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 calc/Calc.java a=c.mul(c.val(2), c.add(c.val(3), c.val(4))); メソッド呼び出し自体,逆ポーランドの展開される. mainメソッド内のアセンブラ参照 2 val 3 val 4 val add mull

invokevirtual インスタンスメソッドの呼び出し 例 invokevirtual Calc/val(I)I これによって,新しいフレームが生成される. 返り値がV(void)でない限り,返り値はすぐ下のフレームのオペランドスタックに載せられる.(これがメソッドの返り値)

例題のトーレス 1/11 main .method .... main ..... aload_1 オペランド iconst_2 スタック ローカル 変数 main .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 local=[args, c, ] stack=[c, c, 2] invokevirtual Calc/val(I)I スタック上からcと2をとって,valを呼び出す. インスタンスメソッドなのでターゲットインスタンスリファレンス(c)が必要. 2はval自体の引数.

例題のトーレス 2/11 main val(2) .method val(I)I .limit stack 1 .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 オペランド スタック ローカル 変数 main オペランド スタック ローカル 変数 val(2) .method val(I)I .limit stack 1 .limit locals 2 iload_1 ireturn .end method 2が帰る local=[this, 2] stack=[] iload_1 local=[this, 2] stack=[2] ireturn

例題のトーレス 3/11 main .method .... main ..... aload_1 オペランド iconst_2 スタック ローカル 変数 main .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 local=[args, c, ] stack=[c, c, 2] invokevirtual Calc/val(I)I local=[args, c, ] stack=[c, 2] aload_1 iconst_3 local=[args, c, ] stack=[c,2,c,c,3]

例題のトーレス 4/11 .method val(I)I main val(3) .limit stack 1 .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 .method val(I)I .limit stack 1 .limit locals 2 iload_1 ireturn .end method オペランド スタック ローカル 変数 main オペランド スタック ローカル 変数 val(3) 3が帰る ..... local=[args, c, ] stack=[c,2,c,c,3] invokevirtual Calc/val(I)I local=[args, c, ] stack=[c,2,c,3]

例題のトーレス 5/11 main .method .... main ..... aload_1 iconst_2 オペランド invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 オペランド スタック ローカル 変数 main ..... local=[args, c, ] stack=[c,2,c,3] aload_1 iconst_4 local=[args, c, ] stack=[c,2,c,3,c,4]

例題のトーレス 6/11 .method val(I)I main val(4) .limit stack 1 .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 .method val(I)I .limit stack 1 .limit locals 2 iload_1 ireturn .end method オペランド スタック ローカル 変数 main オペランド スタック ローカル 変数 val(4) 4が帰る ..... local=[args, c, ] stack=[c,2,c,3,c,4] invokevirtual Calc/val(I)I local=[args, c, ] stack=[c,2,c,3,4]

例題のトーレス 7/11 main add(3,4) .method add(II)I .limit stack 2 .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 オペランド スタック ローカル 変数 main オペランド スタック ローカル 変数 add(3,4) .method add(II)I .limit stack 2 .limit locals 3 iload_1 iload_2 iadd ireturn .end method ..... local=[args, c, ] stack=[c,2,c,3,4] invokevirtual Clac/add(II)I

例題のトーレス 8/11 main add(3,4) .method add(II)I .limit stack 2 オペランド スタック ローカル 変数 main オペランド スタック ローカル 変数 add(3,4) .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 .method add(II)I .limit stack 2 .limit locals 3 iload_1 iload_2 iadd ireturn .end method 7が返る local=[this,3,4] stack=[] iload_1 iload_2 local=[this,3,4] stack=[3,4] iadd local=[this,3,4] stack=[7] ireturn

例題のトーレス 9/11 main mul(2,7) .method mul(II)I .limit stack 2 .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 オペランド スタック ローカル 変数 main オペランド スタック ローカル 変数 mul(2,7) .method mul(II)I .limit stack 2 .limit locals 3 iload_1 iload_2 imul ireturn .end method ..... local=[args, c, ] stack=[c,2,c,3,4] invokevirtual Clac/add(II)I local=[args, c, ] stack=[c,2,7] invokevirtual Calc/mul(II)I

例題のトーレス 10/11 main mul(2,7) .method mul(II)I .limit stack 2 オペランド スタック ローカル 変数 main オペランド スタック ローカル 変数 mul(2,7) .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 .method mul(II)I .limit stack 2 .limit locals 3 iload_1 iload_2 imul ireturn .end method 14が返る local=[this,2,7] stack=[] iload_1 iload_2 local=[this,2,7] stack=[2,7] imul local=[this,2,7]stack=[14] ireturn

例題のトーレス 11/11 main mul(2,7) .method mul(II)I .limit stack 2 .method .... main ..... aload_1 iconst_2 invokevirtual Calc/val(I)I iconst_3 iconst_4 invokevirtual Calc/add(II)I invokevirtual Calc/mul(II)I istore_2 オペランド スタック ローカル 変数 main オペランド スタック ローカル 変数 mul(2,7) .method mul(II)I .limit stack 2 .limit locals 3 iload_1 iload_2 imul ireturn .end method ..... local=[args, c, ] stack=[c,2,7] invokevirtual Calc/mul(II)I local=[args, c, ] stack=[14] istore_2 local=[args, c, 14]

トレースの感想 つ,疲れる. 単純作業を正確にこなすコンピュータの奇跡に驚嘆.(人間に無理) インスタンスのリファレンスがほとんど無駄に見えたけど,これに関しては,methodの入れ子呼び出しを行っていないため. Javaスタック内のフレームが2個以上になってない. mainメソッド上からの呼び出しなので,例題が悪かった....

再帰 詳細は rpower/ の下を参照. 解説はWebページを参照. int rpower(int a, int b){ .method rpower(II)I .limit stack 5 .limit locals 3 iload_2 ifle Label1 iload_1 aload_0 iconst_1 isub invokevirtual Calc/rpower(II)I imul ireturn Label1: .end method 詳細は rpower/ の下を参照. 解説はWebページを参照. int rpower(int a, int b){ if(b>0) return a * rpower(a, b-1); else return 1; }

インスタンス変数 increment and decrement methods. 初期値を10にして, 3増やして,inc(3) class IncDec{ private int s; IncDec(int a){ s=a; } void inc(int a){ s+=a; } void dec(int a){ s-=a; } int value(){return s;} public static void main(String[] args){ IncDec id=new IncDec(10); id.inc(3); id.dec(8); System.out.println(id.value()); } increment and decrement methods. 初期値を10にして, 3増やして,inc(3) 8減らす dec(8) という.... な計算.

静的メソッド,変数 詳細は webページ static/ を参照. invokestatic getstatic / putstatic .class public Static .super java/lang/Object .field private static v I .method static add(I)V .limit stack 2 .limit locals 1 getstatic Static/v I iload_0 iadd putstatic Static/v I return .end method 詳細は webページ static/ を参照. invokestatic getstatic / putstatic ローカル変数0 にインスタンスが入らない. 静的変数は名前がそのまま残る.(vなど) static int v; static void add(int a){v += a;}

静的変数の初期化 .class InitStatic class InitStatic{ .super java/lang/Object .field static uptoval I .field val I ; 中略 .method static <clinit>()V .limit stack 1 .limit locals 0 bipush 100 putstatic InitStatic/uptoval I return .end method class InitStatic{ static int uptoval=100; int val; boolean add(int a){ if(val+a>uptoval) return false; else val += a; return true; }

変数操作のまとめ インスタンス変数 静的変数 getfield p.302 putfield p.444 getstatic p.306 putstatic p.447

コンストラクタ デフォルトのコンストラクタ 明示的に再定義した場合 明示的にスーパークラスを指定 実装するインタフェースを指定

デフォルトコンストラクタ 例えば,calc/の例など. デフォではObjectのサブクラスなので,そのコンストラクタを呼んでいる. .class public Calc .super java/lang/Object .method public <init>()V .limit stack 1 .limit locals 1 aload_0 invokespecial java/lang/Object/<init>()V return .end method

明示的に再定義 例えば, inc-dec/ の例など. デフォルトのコンストラクタは無くなる. それでも,superの初期化はする. .class IncDec .super java/lang/Object .field private s I .method <init>(I)V .limit stack 2 .limit locals 2 aload_0 invokespecial java/lang/Object/<init>()V iload_1 putfield IncDec/s I return .end method class IncDec{ private int s; IncDec(int a){ s=a; }

明示的なスーパークラス 明示的再定義とそう変わらない. .class MyThread class MyThread .super java/lang/Thread .field private s I .method <init>(I)V .limit stack 2 .limit locals 2 aload_0 invokespecial java/lang/Thread/<init>()V iload_1 putfield MyThread/s I return .end method class MyThread extends Thread{ private int s; MyThread(int s){ this.s=s; }

明示的スーパークラス その2 public class Supers extends Super1{ private int ss; super(3,2); ss=4; } class Super1 extends Super2{ private int s1; Super1(int s1, int s2){ super(s2); this.s1=s1; class Super2 { private int s2; Super2(int s2){ this.s2=s2; } .class public Supers .super Super1 .field private ss I .method <init>()V .limit stack 3 .limit locals 1 aload_0 iconst_3 iconst_2 invokespecial Super1/<init>(II)V iconst_4 putfield Supers/ss I return .end method

続き .class Super1 .super Super2 .field private s1 I .method <init>(II)V .limit stack 2 .limit locals 3 aload_0 iload_2 invokespecial Super2/<init>(I)V iload_1 putfield Super1/s1 I return .end method .class Super2 .super java/lang/Object .field private s2 I .method <init>(I)V .limit stack 2 .limit locals 2 aload_0 invokespecial java/lang/Object/<init>()V iload_1 putfield Super2/s2 I return .end method

インタフェースの実装 実装してるインタフェース情報が追加されている. importは展開されている. .class public MyVector .super java/util/Vector .implements java/lang/Runnable .method public <init>()V .limit stack 1 .limit locals 1 aload_0 invokespecial java/util/Vector/<init>()V return .end method .method public run()V .limit stack 0 import java.util.*; public class MyVector extends Vector implements Runnable{ public void run(){ } } 実装してるインタフェース情報が追加されている. importは展開されている.

インスタンスの作成 new クラス名 必要なヒープ確保がされるだけ. 初期設定は明示的に他で. .limit stack 3 .limit locals 2 new MyThread dup iconst_3 invokespecial MyThread/<init>(I)V astore_1 return class MyThread extends Thread{ private int s; MyThread(int s){ this.s=s; } public static void main(String[] args){ MyThread m=new MyThread(3); 通常は,後の操作のため,参照の複製を作る.(dup) その複製をローカル変数へ書き込む.(astore_?)

メソッド呼び出しのまとめ invokespecial 下記のメソッド呼び出し p.364 インスタンス初期化 privateなインスタンスメソッド superのインスタンスメソッド invokevirtual 上記以外のインスタンスメソッド p.372 invokestatic 静的メソッド p.369 invokeinterface インタフェースのメソッド p.361