Warcraft3のMOD総合案内
- Jass Script/メモリリーク の編集
[
ファイルを添付する
] [
このページの名前を変更する
] [
このページを編集する
]
サイトメニュー
ページ一覧
最近の更新ページ
使い方
トップへ戻る
Jass講座
[[トップ>FrontPage]] > [[MAP作成]] > [[トリガーエディタ]] > [[Jass Script]] > メモリリーク メモリリークのないMAP作りを行う方法。 &color(red){''Jass NewGenの導入が前提''};です。導入せずとも利用できる内容も一部ありますが、あったほうが断然有利です。 ---- #contents ---- *メモリリークとは? [#cb652f35] :メモリリーク/memory leak|利用可能なメモリ容量が、徐々に減っていく現象。 ゲームを続けていくと、だんだんと処理が重くなるようなMAPはありませんか?それはPCのメモリ不足が原因です。World Editorでは、一部の変数をのぞいて、変数等は正しく破棄しないと、処理が終了してもPC上のメモリに残り続け、メモリ容量を圧迫->メモリリークを起こします。 メモリ不足は、ユニット数が異常に多いとき、スペルエフェクト等が激しすぎる時などに、''一時的に''みられる場合もあります。これはメモリリークとは関係なく、それらが消え去れば症状も改善されます。 メモリリークがあるMAPの場合、プレイを続けていくにつれて徐々に処理が重くなってしまい、ゲームの快適性を大きく損ねます。 *メモリリークを防ぐには [#g354b187] call Destroy〜 を必ず呼ぶ real, integer, boolean以外は、使い終わったら set ○○ = null を徹底する 〜BJ な、''Blizzard.j'' で定義されている関数は、安全が確認されているもの以外使わない。 *具体的な対策 [#q50abfc5] **handle型変数のnull化 [#bbec96d7] handle型の変数はすべて、利用後に ''null'' を代入することで、メモリからデータを消去する必要がある。handle型の変数は、[[変数型>Jass Script/変数型]] のページにあるように、''integer'', ''real'', ''boolean'' 型以外の全ての変数。 具体的には、以下のようになる。 function Sample takes player whichPlayer returns nothing local item whichItem = GetManipulatedItem() local real whichReal = GetRandomReal(0.00,1.11) local string whichString = "SampleString" local unit whichUnit = GetManipulatingUnit() //ここに何かしら処理がある //処理終了。以下、handle型変数のnull化 // item 型とunit型は、ともにwidget型の派生。 //widget型は、handle型の派生であるから、null化する必要がある。 // player 型も handle 型の派生だが、 //takes 〜 で渡された数字は、null化してはいけない。 //※引数をnull化すると、関数をcallしたときに設定した変数がnull化されてしまう。 set whichItem = null set i = null endfunction **オブジェクトの破棄 [#n9fc59b9] 以下のオブジェクトは、利用後にそれぞれ専用の関数で破棄しなければならない。また、これは必ず&color(red){null化の''前に''};行うこと。 :boolexpr|call DestroyBoolExpr(whichBoolExpr) :conditionfunc|call DestroyCondition(whichConditionFunc) :defeatcondition|call DestroyDefeatCondition(whichDefeatCondition) :effect|call DestroyEffect(whichEffect) :filterfunc|call DestroyFilter(whichFilterFunc) :fogmodifier|call DestroyFogModifier(whichFogModifier) :force|call DestroyForce(whichForce) :group|call DestroyGroup(whichGroup) :image|call DestroyImage(whichImage) :itempool|call DestroyItemPool(whichItemPool) :leaderboard|call DestroyLeaderboard(whichLeaderboard) :lightning|call DestroyLightning(whichLightning) :multiboard|call DestroyMultiboard(whichMultiboard) :quest|call DestroyQuest(whichQuest) :texttag|call DestroyTextTag(whichTextTag) :timer|call DestroyTimer(whichTimer) :timerdialog|call DestroyTimerDialog(whichTimerDialog) :trigger|call DestroyTrigger(whichTrigger) :ubersplat|call DestroyUbersplat(whichUbersplat) :unitpool|call DestroyUnitPool(whichUnitPool) :gamecache|call FlushGameCache(whichGameCache) :unit|call RemoveUnit(whichUnit) :item|call RemoveItem(whichItem) :location|call RemoveLocation(whichLocation) :rect|call RemoveRect(whichRect) :region|call RemoveRegion(whichRegion) :weathereffect|call RemoveWeatherEffect(whichWeatherEffect) *製作のヒント [#s9b74e6a] **handle型変数の戻り値を返す [#qd38bf30] 以上のことを理解できたら、以下の関数はメモリリークが発生してしまうことがわかるだろう。 //メモリリークを起こす例 function CreateUnitLocust takes player whichPlayer returns unit local unit newUnit = CreateUnit(whichPlayer,'hpea',0,0,0) //作成したユニットを、Locustに設定する call UnitAddAbility(newUnit,'Aloc') return newUnit endfunction どこでメモリリークを起こすかわかるだろうか。そう、ローカル変数 ''newUnit'' がnull化されていない点だ。ではどうすればよいか。まず、ダメな回答例をあげる。 //メモリリークを起こさない例 function CreateUnitLocust takes player whichPlayer returns unit //Blizzard.j で定義されているグローバル変数、bj_lastCreatedUnit を使う set bj_lastCreatedUnit = CreateUnit(whichPlayer,'hpea',0,0,0) //作成したユニットを、Locustに設定する call UnitAddAbility(bj_lastCreatedUnit,'Aloc') return bj_lastCreatedUnit endfunction 最初からローカル変数を定義しなければよいのだが、これは例としてあまりに不適切な''ウンコ回答''なのでスルーしてもらいたい。誤作動の元になりうる。((グローバル変数を使うと、もしこのfunctionが実行に時間のかかるものであれば、二重に呼び出されたときなどに ''bj_lastCreatedUnit'' が書き換えられてしまうこともあるからだ))上の例は無視しよう。 では、どうすればよいか。以下が正式な回答だ。 //handle型変数を、Integerに変換 function H2I takes handle h returns integer return h return 0 endfunction //メモリリークを起こさない例 function CreateUnitLocust takes player whichPlayer returns unit local unit newUnit = CreateUnit(whichPlayer,'hpea',0,0,0) //ユニットのhandleを、Integer型で格納する。 local integer newUnitHandle = H2I(newUnit) //作成したユニットを、Locustに設定する call UnitAddAbility(newUnit,'Aloc') //メモリリーク対策。newUnit変数を開放 set newUnit = null // integer型を返す操作になるが、 //integer型とhandle型は等価であるからエラーは発生しない。 // また、この関数の戻り値は unit型に設定されているので、 //戻り値のintegerは、この関数の呼び出し元では //handle型->widget型->unit型として処理される。 return newUnitHandle // 形式上はユニット型を返さないとコンパイルエラーが起こるので、 //ここではreturn null を末尾に記入。"ただし、実際には実行されない。" return null endfunction まず、integer型でユニットのhandleを格納し、その後にユニットを格納していた変数を開放。最後に、ユニット型変数のかわりに、handleと同じ値を持つinteger型変数を返す。このinteger値は、関数の呼び出し元では本来の戻り値であるはずのunit型変数(=widget=handle)と解釈されるため、正常に動作する。また最終行で、コンパイラのエラーを回避するために null を返す。 ここで利用されている ''H2I'' 関数は、GameCacheなどあらゆるシステムで非常に便利。[[GameCache>Jass Script/GameCache]]の項目でライブラリを公開するので、利用するといいだろう。 :handleとは?|ポインタのようなもので、あらゆるオブジェクトが格納されているメモリ上の場所を示す整数(integer)。integer, real, boolean以外のすべては固有のhandleを持つ。詳しくは、[[変数型>Jass Script/変数型]]の項で。
タイムスタンプを変更しない
[[トップ>FrontPage]] > [[MAP作成]] > [[トリガーエディタ]] > [[Jass Script]] > メモリリーク メモリリークのないMAP作りを行う方法。 &color(red){''Jass NewGenの導入が前提''};です。導入せずとも利用できる内容も一部ありますが、あったほうが断然有利です。 ---- #contents ---- *メモリリークとは? [#cb652f35] :メモリリーク/memory leak|利用可能なメモリ容量が、徐々に減っていく現象。 ゲームを続けていくと、だんだんと処理が重くなるようなMAPはありませんか?それはPCのメモリ不足が原因です。World Editorでは、一部の変数をのぞいて、変数等は正しく破棄しないと、処理が終了してもPC上のメモリに残り続け、メモリ容量を圧迫->メモリリークを起こします。 メモリ不足は、ユニット数が異常に多いとき、スペルエフェクト等が激しすぎる時などに、''一時的に''みられる場合もあります。これはメモリリークとは関係なく、それらが消え去れば症状も改善されます。 メモリリークがあるMAPの場合、プレイを続けていくにつれて徐々に処理が重くなってしまい、ゲームの快適性を大きく損ねます。 *メモリリークを防ぐには [#g354b187] call Destroy〜 を必ず呼ぶ real, integer, boolean以外は、使い終わったら set ○○ = null を徹底する 〜BJ な、''Blizzard.j'' で定義されている関数は、安全が確認されているもの以外使わない。 *具体的な対策 [#q50abfc5] **handle型変数のnull化 [#bbec96d7] handle型の変数はすべて、利用後に ''null'' を代入することで、メモリからデータを消去する必要がある。handle型の変数は、[[変数型>Jass Script/変数型]] のページにあるように、''integer'', ''real'', ''boolean'' 型以外の全ての変数。 具体的には、以下のようになる。 function Sample takes player whichPlayer returns nothing local item whichItem = GetManipulatedItem() local real whichReal = GetRandomReal(0.00,1.11) local string whichString = "SampleString" local unit whichUnit = GetManipulatingUnit() //ここに何かしら処理がある //処理終了。以下、handle型変数のnull化 // item 型とunit型は、ともにwidget型の派生。 //widget型は、handle型の派生であるから、null化する必要がある。 // player 型も handle 型の派生だが、 //takes 〜 で渡された数字は、null化してはいけない。 //※引数をnull化すると、関数をcallしたときに設定した変数がnull化されてしまう。 set whichItem = null set i = null endfunction **オブジェクトの破棄 [#n9fc59b9] 以下のオブジェクトは、利用後にそれぞれ専用の関数で破棄しなければならない。また、これは必ず&color(red){null化の''前に''};行うこと。 :boolexpr|call DestroyBoolExpr(whichBoolExpr) :conditionfunc|call DestroyCondition(whichConditionFunc) :defeatcondition|call DestroyDefeatCondition(whichDefeatCondition) :effect|call DestroyEffect(whichEffect) :filterfunc|call DestroyFilter(whichFilterFunc) :fogmodifier|call DestroyFogModifier(whichFogModifier) :force|call DestroyForce(whichForce) :group|call DestroyGroup(whichGroup) :image|call DestroyImage(whichImage) :itempool|call DestroyItemPool(whichItemPool) :leaderboard|call DestroyLeaderboard(whichLeaderboard) :lightning|call DestroyLightning(whichLightning) :multiboard|call DestroyMultiboard(whichMultiboard) :quest|call DestroyQuest(whichQuest) :texttag|call DestroyTextTag(whichTextTag) :timer|call DestroyTimer(whichTimer) :timerdialog|call DestroyTimerDialog(whichTimerDialog) :trigger|call DestroyTrigger(whichTrigger) :ubersplat|call DestroyUbersplat(whichUbersplat) :unitpool|call DestroyUnitPool(whichUnitPool) :gamecache|call FlushGameCache(whichGameCache) :unit|call RemoveUnit(whichUnit) :item|call RemoveItem(whichItem) :location|call RemoveLocation(whichLocation) :rect|call RemoveRect(whichRect) :region|call RemoveRegion(whichRegion) :weathereffect|call RemoveWeatherEffect(whichWeatherEffect) *製作のヒント [#s9b74e6a] **handle型変数の戻り値を返す [#qd38bf30] 以上のことを理解できたら、以下の関数はメモリリークが発生してしまうことがわかるだろう。 //メモリリークを起こす例 function CreateUnitLocust takes player whichPlayer returns unit local unit newUnit = CreateUnit(whichPlayer,'hpea',0,0,0) //作成したユニットを、Locustに設定する call UnitAddAbility(newUnit,'Aloc') return newUnit endfunction どこでメモリリークを起こすかわかるだろうか。そう、ローカル変数 ''newUnit'' がnull化されていない点だ。ではどうすればよいか。まず、ダメな回答例をあげる。 //メモリリークを起こさない例 function CreateUnitLocust takes player whichPlayer returns unit //Blizzard.j で定義されているグローバル変数、bj_lastCreatedUnit を使う set bj_lastCreatedUnit = CreateUnit(whichPlayer,'hpea',0,0,0) //作成したユニットを、Locustに設定する call UnitAddAbility(bj_lastCreatedUnit,'Aloc') return bj_lastCreatedUnit endfunction 最初からローカル変数を定義しなければよいのだが、これは例としてあまりに不適切な''ウンコ回答''なのでスルーしてもらいたい。誤作動の元になりうる。((グローバル変数を使うと、もしこのfunctionが実行に時間のかかるものであれば、二重に呼び出されたときなどに ''bj_lastCreatedUnit'' が書き換えられてしまうこともあるからだ))上の例は無視しよう。 では、どうすればよいか。以下が正式な回答だ。 //handle型変数を、Integerに変換 function H2I takes handle h returns integer return h return 0 endfunction //メモリリークを起こさない例 function CreateUnitLocust takes player whichPlayer returns unit local unit newUnit = CreateUnit(whichPlayer,'hpea',0,0,0) //ユニットのhandleを、Integer型で格納する。 local integer newUnitHandle = H2I(newUnit) //作成したユニットを、Locustに設定する call UnitAddAbility(newUnit,'Aloc') //メモリリーク対策。newUnit変数を開放 set newUnit = null // integer型を返す操作になるが、 //integer型とhandle型は等価であるからエラーは発生しない。 // また、この関数の戻り値は unit型に設定されているので、 //戻り値のintegerは、この関数の呼び出し元では //handle型->widget型->unit型として処理される。 return newUnitHandle // 形式上はユニット型を返さないとコンパイルエラーが起こるので、 //ここではreturn null を末尾に記入。"ただし、実際には実行されない。" return null endfunction まず、integer型でユニットのhandleを格納し、その後にユニットを格納していた変数を開放。最後に、ユニット型変数のかわりに、handleと同じ値を持つinteger型変数を返す。このinteger値は、関数の呼び出し元では本来の戻り値であるはずのunit型変数(=widget=handle)と解釈されるため、正常に動作する。また最終行で、コンパイラのエラーを回避するために null を返す。 ここで利用されている ''H2I'' 関数は、GameCacheなどあらゆるシステムで非常に便利。[[GameCache>Jass Script/GameCache]]の項目でライブラリを公開するので、利用するといいだろう。 :handleとは?|ポインタのようなもので、あらゆるオブジェクトが格納されているメモリ上の場所を示す整数(integer)。integer, real, boolean以外のすべては固有のhandleを持つ。詳しくは、[[変数型>Jass Script/変数型]]の項で。
テキスト整形のルールを表示する