セカンドライフでもメモリの使用量については
よく考えて作らないといけません。
セカンドライフではプログラムは一度バイトコードに変換されて、
プロセス仮想マシンによって動いています。
SL上で動作している仮想マシンは2種類あります。
・LSO
・Mono (wikia)
このMonoというのは.NETの仮想マシンにも利用されているもので、
2007年~2008年ごろからセカンドライフに導入されたものです。
何が違うかは、Monoのwikiを見るとわかりますが、Monoの方が色々とすぐれています。
例えば、メモリ使用量なのですが、
・LSO 固定16KB ( 16384 バイト )
・Mono 最大64KB ( 65536 バイト )
となっています。
LSOは、プログラム1つ1つに固定のメモリサイズ16KBを割り当てているのに対して、
Monoは、その場その場でメモリを確保していくタイプになっています。
最大64KBも使用していいのかという話になりますが、
同じSIM内に同一のプログラムがあればメモリを共有するため、
全体的に見ればLSOより使用メモリは少なくなるためのようです。
また、速度もLSOより、早いためMonoを使った方がいいです。
さて、メモリの話に戻るのですが、
メモリの話は、現在のスクリプトの空きメモリ使用量を取得する
「llGetFreeMemory」のところに詳しく書いてあります。
これから自分の中で理解した範囲を要約して書き出します。
間違っていることも多分あるため少し疑って読んだ方がいいかもしれません。
メモリは下記の4種類で、利用されており、合計が使用メモリとなります。
・バイト コード
プログラムをコンパイルしたあとの最小限のコードです。
Monoのほうが、LSOよりバイトコードが最大4倍長いですが、他に同一のプログラムがあれば共用されます。
・スタック
プログラムの中の長い1行の計算式を計算する際や、関数を呼び出したときに一時的に使用するメモリです。
これは、関数から戻ってきたときや、1行の計算が終わった際に解放されます。
string、list、keyのポインタ、数値型など数値データは、スタックに記録されます。
・空きメモリ
使用していない領域です。スタックやヒープを使用すると減っていきます。
llGetFreeMemory関数で取得することができます。
・ヒープ
ヒープは、文字列、KEY、リストを使用すると確保されるメモリ領域です。
関数内で定義した場合は、抜ければ解放されると思いますが、いまいちよく分かりません。
なお、wikiによるとヒープ領域は例え解放できたとしても、
断片化によってメモリが再利用できない場合があるようです。
例として、4バイトの空き容量がちらばって合計10KBあったとしても、
メモリを連ねて必要な文字列などとして利用できないということです。
なお、llGetFreeMemory に書いてあるように、
スタックやヒープに使用可能な空きメモリが無くなると、
Stack-Heap Collision エラーが発生して、スクリプトは異常終了するようです。
下記の短いスクリプトは目印とその時の空き容量を表示するものです。
printMemory(integer num) { integer memory_byte = llGetFreeMemory(); llOwnerSay("[" + (string)num + "] " + (string)memory_byte + "byte"); }
このスクリプトをいろいろな箇所に入れてみて、
どのようにメモリが推移するかを見てみるといいかもしれません。
値が一定となり、それより増えることがなければ、安定しているといえます。
本当は、今回の章ではどの段階でメモリが解放されるのか、
いろいろ調べていきたいと思ったのですが、テスト用スクリプトを作っていると、
突然アップロードできなくなり、再ログインに失敗するようになったため、
(ログインしようとしたらシステムからログアウトされました。
太平洋時間の何時までログインできないみたいなメッセージが表示されます)
ちょっと調べることができませんでした。(^○^)
とりあえず自分で書いて分かったことは、
・関数内でlistを使用してあれこれした後、関数を抜けるとlistは解放される
・ブロック分で変数を使用した場合、ブロックから抜けてもメモリは解放されていない
・関数から抜けたタイミングで解放できるメモリを開放する
ぐらいでした。
Monoの場合は、メモリの開放を自動でやってくれるかどうかとかも
調べたいと思ったのですが、今回は断念します。
「メモリ管理問題が解決しないではないか」と嘆くかたもいると思いますが、
良い解決方法があります。
組み込み系(電化製品のCPUのためのプログラム)などではよく利用されると
思うのですのが、ウォッチドッグタイマというものがあります。
ウォッチドッグというのは、定期的に番犬が見張っていて、
(ここでいうとプログラムが正常に動いているか見張っていまして、)
これが動いていないとなると、ウォッチドッグリセットを走らせます。
セカンドライフにおける様々なプログラムは、
サーバー上でずっと動き続けることを前提としてプログラムしなければなりません。
そういう点では組み込み系に少しだけ似ているかもしれません。
そこで、セカンドライフ上のプログラムでも組み込み系と同じように
定期的に正しく動いているか、ここではメモリの空き容量を調べて、
上限を超えたらリセットさせるというプログラムをすればいいことが分かります。
リセットは下記のスクリプトで行うことができます。
llResetScript();
タイマーを使用して、定期的に自分のメモリサイズを調べる。
あるいは、何か大きな処理をする前にメモリサイズを調べるといったことを行い、
制限値を超えていれば llResetScript を、
走らせてプログラムを最初から実行させるということです。
あるいは複雑なプログラムではリセットを前提とした
プログラムをしてもいいかもしれません。
今回、いろいろ調べようと思ったのですが、
上記のような形で、終わりです。なんだかスミマセン
以上!
ちなみにこんなのでました。
サーバーが安定して時間があれば調べたいと思います。
コメント