Mopsの
動的オブジェクトの標準コンテナは、その名の通りハンドルを利用します。ハンドルとして確保された領域は、必要に応じてヒープメモリーの中を移動させられます。これは、かつてメモリーが希少であった頃、メモリー利用の断片化による利用効率低下を避けようとして開発された技巧です。しかし、現在では、実行速度も含めて考えたメモリー利用効率のためにハンドルを用いる利点はほとんどないといわれています。特に、固定したベースアドレスが欲しいGUIオブジェクト(ウィンドウやダイアログ)では、思いがけないエラーに見舞われることもあるかもしれません(これは私がMopsで最初に躓いた"石"でした(^^;;)。具体的には、ベースアドレスを予め登録して、後でそれを用いてメソッドを送る必要があるオブジェクトで、Mopsのデフォルトでは、ダイアローグ(アラート)、ウィンドウが問題となり得ます。ポイントはこれらがカーボンイベントを受け取ることです。Unlock:に関する条件はこの事実を前提としたものです。そのうち、ポインタ(動かない)を使ったオブジェクトリストの作成例を説明したいと思っています。容易ですから、練習としてご自身で作ってみるのもよいかと思います。
動的オブジェクトのコンテナとしてObjHandleクラスを使います。
動的オブジェクト(ヒープオブジェクト)には名前がありません。確かにコンテナとなるオブジェクトには名前がありますが、そのクラスと生成したいオブジェクトのクラスのクラスは、普通は違います。コンテナとなるオブジェクトには、直接には、そのクラスで理解できるメッセージしか送ることはできません。
そのため、動的オブジェクトにメッセージを送るには、そのベースアドレスをスタックに置く構文を使う必要があります。クラスがはっきりしているのであればEarly bindで、可変にしてポリモルフィズムを実現したいときなどはLate Bindで書けばよいでしょう。動的オブジェクトのアドレスを取るには、コンテナとなっているObjHandleに"OBJ:"メッセージを送ります。例えば、動的オブジェクトに"GET:"というメッセージを送りたいときには、
OBJ: MyDynamicObj GET: class_as> クラス名
GET: [ OBJ: MyDynamicObj ]
OBJ: MyDynamicObj GET: []
OBJ: MyDynamicObj GET: **
の4つ(厳密には"class_as>"を省く書き方もあるので5つ!)のやり方があります。"クラス名"は、もちろん、バインドしたいメソッドのクラス名を書くということです。最初のものだけが、Early Bind(早期束縛。別名static bind:静的束縛)になります。スタイルは、好ましいと思われるものを使えばよいでしょう。パラメタが必要なときには、当然ですが、上のような形のメッセージバインドコードよりも前(左側)にスタックに数値を揃えておきます。
ここで、"OBJ:"というメッセージが実際には何をするのかについて説明しなければなりません。まず、ヒープ上に生成されたオブジェクトデータのための領域は、邪魔にならないように、ハイメモリに移動されます。ハイメモリとは、メモリーの上の方ということで、要は、メモリのアドレス番号が(符号無し数値として)大きい方ということです。それから、オブジェクトデータにアクセス中に移動されたりしないように、領域を固定します("LOCK"(ロック)といいます。"LOCK:"というメソッドもあります。)それから、オブジェクトのベースアドレスに当たるメモリーアドレスの値をスタックに返します。
ハイメモリーへの移動は、Mac OS Xでは実施されないようです。また、動的オブジェクトのために確保したヒープ領域を増やそうとしたりしない限り、オブジェクトが移動されることはないようです。またiMopsでは、Lock: Unlock:は全く不要で、メソッド自体がありません。したがって、Mac OS X以降は、ロックに関わる部分の記述は不要です。
つまり、"OBJ:"メッセージを送った後は、ヒープオブジェクトは移動できない状態に止まってしまいます。そこで、普通は、一通りメッセージの送付が終わったら、"UNLOCK:"メッセージを送って移動できるようにして、メモリーの断片化を防ぎます、と書かれてきました。一般にはいまでも断片化の危険は存在するのですが、PowerMopsではあまり大きな問題ではなくなりました。特に、OS Xでは常に4GBの仮想メモリー領域が準備されており、必要に応じてアプリケーションに配分されるので、極論すれば、相当非効率的な使い方をしても問題は出ないといえます。OS 9においても、メモリーはかなり大きくなっていますし、上に寄せてあるので、問題が出ることはないでしょう。したがって、長期間存続するオブジェクトでも、UNLOCK:する必要はあまりないといえます。特に、GUIオブジェクトでは、Carbonイベントを処理するためのコールバックは、
はじめに登録されたベースアドレスを使ってメッセージをバインドするので、これが事後的に動くと予想外の結果が生じ、クラッシュにつながります。このようなオブジェクトでは、むしろUNLOCK:してはいけません。
関連項目:
最終更新:2018年12月23日 16:21