2006/12/9

調べてみたら意外なことがわかった  VRMスクリプト禅問答
コレの続き。まぁ、大半の読者にとってはどーでもいい話だと思うので、気になる人だけ続きをどうぞ。


結論から言うと、近ちゃん氏が気にしていた“SetEventAfter命令を使った繰り返し実行によってメモリリークが起きるのではないか”という不安は杞憂だ。近ちゃんに限らず、諸兄も気にせずにバンバン使っていただきたい、使えるのなら。

で、この実験の過程で、表題にも書いたように「意外なこと」に気づいた(まぁ、結果から振り返るとそりゃそーだわな、って話なんだけども)ので、それを報告すべく、どんな実験をやったのかを説明していくことにする。

*     *     *

まず、前回予告していた通りの実験をやった。図にするとこんな感じ。

クリックすると元のサイズで表示します

それぞれの□がメソッドだと思って欲しい。最初の左端の□は、オブジェクトの宣言部で、右へ伸びる五本の矢印は、それぞれがSetEvnetAfter命令で次のメソッドの実行イベントを設定したことを意味している。最初を除き、他の□からは次のメソッド1つだけに対しSetEventAfter命令を仕掛けている。実際には、若干の時間差を設けているので、図のように整然と並んで実行されるのではなく、バラバラと五月雨的に併走実行されることになる。

さて、それぞれの□=メソッドでは255個のローカル変数を宣言しているので、これが新たに必要なメモリ領域としてWindowsから借用(いわゆるallocate)され、結果的にタスクマネージャから見えるVRMビュワーのメモリ使用量の増加として観測される。前回も書いたように、メモリリークが発生するのであればこれが漸増するはずだが、実行開始時に微増した以外、数分動作させても(テストでは→の間隔は数ミリ秒であり、この数分は普通の使い方での1時間以上に相当すると考えて良い)変化は起こらなかった。つまり、メモリリークは発生しない、ということになる。

さて。ここでちょっと茶目っけが生まれて、さらに過酷なテストをやってみる気になった。いや、結果から言うと過酷でも何でもなかったんだけども。

クリックすると元のサイズで表示します

基本的な考え方は最初の実験と同じだが、それぞれのメソッドは2つのメソッドに対してSetEventAfterをする。つまり、時間経過につれて同時実行されるメソッドの数が鼠算式に増えていく、という仕掛けである。もし、VRMからWindowsに対するメモリの借用が、併走するメソッド間でまったく同時におこなわれるのであれば、アッという間にWindowsの物理/仮想メモリ領域を食いつぶしてWindowsがお亡くなりになるはずである。

で、やってみたら、最初の実験同様にメモリ使用量は微増したのみで、安定してしまった。クラッシュを期待していたので拍子抜けである。これは何を意味しているのか。

話は簡単で、上に書いたような「衒学的な図」で考えていたがために生じた誤解に振り回されていただけなのだ。断言は出来ないが、VRM内部の動作から見たSetEventAfter命令というのは、SetEventAfterイベント実行エンジン(と仮に呼ぶ)という1ミリ秒毎に待ち行列を検査して実行待ちになっているメソッドがいればそれを1つ実行する仕組みに対し、「その待ち行列に並べ」とメソッドを送り込む命令に過ぎないのだ。

従って、理屈の上では上掲図のようにたくさんのメソッドが同時に実行され、その分だけメモリが消費されるように思えるこの実験も、実は単にメモリを消費する処理として実行されるメソッドの待ち行列が増えてダダ混みになるだけの話であって、決してそれでメモリリークであるとか、ましてやOSクラッシュなんて起きないのである。

ただし、この待ち行列に並んでいる人の中にはビュワーを操作するためのキー/マウス入力なんかもいる(厳密には系列が異なるはずだが、VRMの仮想マシンからすれば同じようなモンである)ので、実験を開始するとすぐにマウスカーソルが効かなくなる。無駄なテストメソッドにシステムの時間を食い尽くされて(待ち行列を占拠されて)マウス操作を処理する手が空かなくなるという寸法だ。

*     *     *

と、ちょっとした実験と、そこから導かれる“仮説”について述べた。

ボクがこれを書いた意図は、「VRMの中身はこうなっているのだ」と断言するためではない。断言するにはVRMを逆コンパイルしてソースを読む必要があるが、そんなことをするつもりはない。ここに書いたのはブラックボックス的なテストであるからして、実際の実装はまた違っているかも知れない。確実なのは、大なり小なりここで述べたような動作をVRMがしている、ということだ。他に説得力のある仮説が思いついた人は聞かせて欲しい。

で、ボクが言いたいのは、迷信や妄想に取り付かれる前に、こういう風に仮説と検証実験を通して自分で考える癖をつけろ、ということ。まぁ、期待してないけど。
0

2006/12/9  16:02

投稿者:ghost
> スレッドタイマー

基本的な考え方はそんなもんでしょう。

まぁ、VRMの場合、ビュワープロセスの中で描画系のスレッドと制御系のスレッドは以前から疎結合だったようなので、スクリプトだからスレッドタイマーだ、ってワケではないんだと思いますが。

> 方向幕

昨年のレイアウトコンテストに出した作品内でやってます。審査員へのイジワル(笑)として隠し的になってるので見つけにくいとは思いますが。VRM4EGでも言及しているので、もしお手元にあればご参照あれかし。

ボクのVRMスクリプトに関する知見は、大抵のことは http://silver.ap.teacup.com/applet/ghost/msgcate9/archive に書き残しているので、適時ご参照ください。でもって、新たな知見フィードバックしていただけるとありがたいです。

2006/12/8  23:05

投稿者:近ちゃん
ghostさん書き込みお初です。
検証していただいてありがとうございます。
どのように検証して自分なりに納得しようかといろいろ考えていてポロッと私のブログに書き込んでみるとghostさんに食いつかれてしまったようです。
せっかく検証していただいたので私のほうでも他の仮説がないかどうか暇なときに考えてみます。
プログラマネタで申し訳ないのですが、1年ほど前にVB.netでスレッドタイマーを使用して一定時間ごとにDBのレプリケーションを行うプログラムを書いてました。
更新件数が多いとき仕様で定めた一定時間内に更新が完了しない事があるのでレプリケーションを行うプロシージャに排他ロック(SyncLock)をかけておくようにしてました。
レプリケーションを行うプロシージャは一定時間ごとに確実に呼ばれますがロックがかかっているとすぐに実行されずにスレッドプールに溜められ待ち状態になります。
最終的にはプールに溜まったものが問題なくすべて実行されるという結果を確認して安心した記憶があります。
スクリプトマニュアルでSetEventTimerをみた時、あっこれスレッドタイマーに似てるなと思ったわけですがghostさんの仮説を読むと動き的にも似ていそうだなと感じました。
わたし的にはポイントや信号の一定時間毎の状態監視と方向幕を回転させるときのループ処理に安定的に使えたらOKなのでどんどん使うことにします。
方向幕については「回転開始ショートカットキー」でSetEventTimerを作動させて1秒毎に回転させ「ここで止まれショートカットキー」でSetEventTimerを作動をとめるというのが面白そうですが・・・
ghostさんの事ですから、もう既に実装されてるかもしれませんね・・・

コメントを書く

この記事にはコメントを投稿できません




teacup.ブログ “AutoPage”
AutoPage最新お知らせ