オブジェクトはメモリの中でどうなってるの?(Tips-14)
注:今回のお話は VBA にそっくりそのまま適用できるかわかりません。一般的なお話として読んでいただければ嬉しいです。
前回、メモリ内部を「オブジェクト」とだけ表現しました。
せっかくなのでメモリ内部をもう少し拡大して観察したいと思います。
メモリ内は主にスタック領域、メソッドエリア(静的領域)、ヒープ領域に分けて管理されます。
クラスをNew する
まず、New するところから始めます。
今回はクラスの実体化という表現はやめて、クラスのインスタンス化という表現にします。(意味は同じです)
New でメモリのヒープ領域に、クラスで定義されたインスタンス変数の容量を確保します。ここで確保された容量をインスタンスと呼びます。
New した数だけ確保(生成)できます。
この、インスタンスをオブジェクトとも呼びます。
場合によっては別のニュアンスで使い分けされることもありますが、本記事の趣旨ではないので割愛します。
(@_@;)「あれ?メソッドとプロパティはどこ行った?」
安心して下さい。
ちゃんとメモリ内のメソッドエリアと呼ばれる場所にロードされます。
コード情報はインスタンスが複数あっても、1クラスにつき1つしかロードされません。同じクラスの各インスタンスから呼び出されて使いまわされるイメージです。
別のクラスBなどから生成したインスタンスがあっても、そこからはクラスAのコード情報は呼び出せません。逆もまた然りです。
変数でインスタンスを参照する
Set 変数 で、インスタンスを代入します。
といってもデータをまるまる代入するのではなく、インスタンスが存在する場所の先頭アドレスを参照します。
ちなみに図の例では変数をクラスA型で宣言しているので、クラスAから生成したインスタンス以外を参照させようとするとエラーになります。
メソッドを呼び出す
変数1から、メソッドを呼び出してみましょう。
今さら言う必要もないかもしれませんが、メソッドを呼び出すときは
- 対象のインスタンスを参照している変数名.メソッド名(引数)
とします。
これによって先頭アドレス:XXXXXXXX に格納されたインスタンスが処理対象であることが特定できます。
あわせて、そのインスタンスに紐付けられたメソッドが呼び出されます。(別のクラスBなどに同じ名前のメソッド名があったとしても呼び出されない)
メソッドが実行され、必要に応じてインスタンスやローカル変数への読み書きも行われます。
各変数について整理しときましょう。
- 同じクラス内に限りどこからでもアクセスできる。
- 参照されている限り存在する。
- 容量の大きいデータを取り扱うことができる。
ローカル変数
- メソッド内からのみアクセスできる。
- メソッドのルーチンが終了したら破棄される。
メソッドの処理によって何らかの結果が返されます。
メインコードからはインスタンスに対して直接読み書きができないので、メソッドやプロパティが窓口となってやり取りが行われます。
処理の結果は数値や文字列だったり、別のクラスのインスタンス化だったり、画面上の表示変化だったり、様々なものがあるだろうと思います。
その辺はメソッドがどのように作られているかによって変わります。
メソッドが終了したら
スタック領域にあった、引数やローカル変数は破棄されます。
インスタンスへの参照は続いているため、アドレス情報は残されます。(と思われる)
プロシージャが終了したら
インスタンスへの参照はなくなり、アドレス情報・インスタンス・コード情報は破棄されます。
最後に
VBAでは特にメインコード以外は Black box に近く、内部を意識しなくてもプログラミングができるようになっています。逆にいうと、それだけ各オブジェクトの機能の抽象度が高く、部品としての独立性が高くなっているんだともいえます。(Workbookオブジェクト、Worksheetオブジェクト、Rangeオブジェクト・・・・・・等々は New すらしなくても使える)
今回はこの Black box 側を強調して描きたかったので、メインコードは標準モジュール内で動いているかのような書き方をしましたが、実際はメインコードもコンパイル(ソースコード→中間コードに一括変換→機械語に順次変換)されて、静的領域にロードされています。
と、ここまで偉そうに書きましたが実際に自分の目で内部動作を見たわけではありません。メモリダンプを解析する技術があって、実際に自分の目で見たのならもっと自信を持って書けるんですが。
以下の本が参考になります。