ユニティ+ Luaのパフォーマンスの最適化

統一+パフォーマンスの最適化のLUAは、要点をメモを取る必要があり

致命的なgameobj.transform.position 1. = posが開始します
 
文言gameobj.transform.position = posのと同じように、団結では共通して、別のことですが、ウルアに、このようなアプローチの広範な使用は非常に悪いです。なぜ?
 
このコード行は、キーluaapiと勝つために(ウルア+ cstoluaのエクスポートをリストされているウルア関連する重要なステップを呼び出すコードの1行だけなので、それは非常に、非常に多くのことが起こった、もう少し直感的にするために、我々は、gameobjはゲームオブジェクトでいましたタイプ、posが)のVector3です。
 
最初のステップ:
GameObjectWrap.get_transformのLUAは、対応するgameobj.transformをgameobjから入手変換したいです
gameobjでLuaDLL.luanet_rawnetobj LUAは、認識のidのC#になります
ObjectTranslator.TryGetValueは、このIDでObjectTranslatorからゲームオブジェクトのC#のオブジェクトを取得します
gameobject.transform準備そんなに、ここでは最終的には本当にC#のの実装をgameobject.transform取得
ObjectTranslator.AddObjectはIDが割り当てられて変換するために、これはObjectTranslatorへの将来の一見のために保存するために、変換のLUAでこれを表現する形質転換するために使用されます
LuaDLL.luanet_newudataユーザデータのLUAに割り当てられ、LUAを表すために使用されるID、への入金はすぐに変換するために戻りました
あなたはこのtransform.positionようにそれを使用できるように、ユーザデータへのLuaDLL.lua_setmetatableは、メタテーブル取り付け
背後ん仕上げ、変換返すLuaDLL.lua_pushvalue
LuaDLL.lua_rawseti
LuaDLL.lua_remove
 
ステップ2:
TransformWrap.set_positionのLUAはtransform.positionに設定されたPOSをしたいです
LUAでLuaDLL.luanet_rawnetobjは認識のidのC#になるために変換します
ObjectTranslator.TryGetValue、このIDでC#のObjectTranslatorからオブジェクトを変換します
LuaDLL.tolua_getfloat3は、C#にフロート3つの戻り値からするVector3 LUAを取得します
XYZの値を取得する+ lua_tonumber 3回lua_getfield、デ・スタック
lua_pop
transform.position =新規のVector3(x、y、z)はあまり準備し、最後に割り当てtransform.position = POSを実行します
これは、1行のコードは、実際に物事のように多くを行うことです!もし、C ++、ABC =
 
メモリアドレスを取得してからの事を割り当てるよりも多くのx、このような何の最適化の後。しかし、ここでは、頻出値、LUAのスタック、C#の型変換は、すべてのステップは、CPU時間がいっぱいです、それは様々なメモリ割り当ておよびGCの背面の間で考えられていませんでした!
 
今、私たちが歩くしようとしている、いくつかのものは実際には不必要である、それは省略することができます。私たちは、最終的には、最適化に彼を置くことができます。
完成lua_isnumber + lua_tonumber 4回
 
Luaのオブジェクト2.参考のC#、高価
 
あなたはgameobjはちょうどそれがない操作のためのCへの直接のポインタ(実際にやってGCHandleによって、ピン止めすることができますように、C#のオブジェクトの非常に高価な価格となっている、変換から取得したいではなく、どのようにパフォーマンス、上記の例から見ることができますテスト、およびGC管理によりピン止めされないが)、したがって主流LUA + UnityがC#でのC#オブジェクトのIDによって辞書によって対応するオブジェクトIDに表されています。なぜなら辞書を参照すると同時にだけでなく、LUAの場合にC#のオブジェクトを確保するごみを再利用することはないで引用しています。
 
したがって、LUAからバックC#のIDへ変換オブジェクトと各パラメータは、辞書検索を行い、次に、オブジェクトを表すオブジェクトメソッド呼び出しの各メンバーは、最初のオブジェクトを見つけなければならない、尽くします辞書検索。
 
このオブジェクトは、LUAに使用するとGCされていない前に場合は、チェックするために次のことは、それも辞書です。しかし、場合には、長いリストの上の例で作業する準備ができているオブジェクトで使用されていない新しいLUAであることが判明します。
 
あなたはそれとLUAでのみ一時的に返されるオブジェクトならば、状況はさらに悪くなります!ただ、割り当てられたユーザデータと辞書インデックスが参照するLUAはGCして除去する、そしてあなたは、このオブジェクトを使用して、次の時間は、あなたが繰り返し、流通GC、パフォーマンスの低下が生じ、再びすべての準備作業をしなければならない可能性があります。
 
gameobj.transformの例ではので、巨大な罠です。バックたびにあなたを導く、すぐLUAを解放されます、一時的なリターン、それを変換しますが、参照をバックアップしませんでした。一度変換、それが流通し、GCを意味するかもしれません。
 
3. LUAとC#(のVector3 /四元など)の間の伝送の統一値のユニークなタイプは、より高価
 
以来、すべてのは、C#を通過vector3.x場合、以前、LUA遅いC#のオブジェクトを呼び出すと、そのパフォーマンスは、基本的に崩壊しているので、プログラムは、純粋なLuaのコードの主流のVector3他の種類を達成する、のVector3は{xとします、Y、Z}テーブルにおいて、使用中のLuaの速いように。
 
#C、しかし、そうすること、そして彼はLUAのVector3は、2つの事柄に完全になるであろう発現後、伝送パラメータは、例えば、C#のするVector3パスLUAは、全体のプロセスは以下の通りである、変換のC#の種類とLUAタイプに関連します。
  1. C#のVector3は、x、y、zの三つの値で取得します
  2. Luaのスタックにこれら三つのfloatを押します
  3. 次いで、テーブル、X、Y、Z割り当てのテーブルを構築します
  4. これは、テーブルに戻り値をプッシュします
テーブル3が挿入された3つのプッシュパラメータメモリ割り当てテーブルを完成するのに必要な単純なパスパラメータが、パフォーマンスが想像できます。
 
それでは、どのようにそれを最適化するには?私たちのテストでは、伝達関数の直接3つのフロートは、転送のVector3よりも高速であることを示しています。
例えばボイドSetPos(ゲームオブジェクトOBJ、Vector3pos)はSetPosを無効にする(ゲームオブジェクトOBJ、フロートX、フワッ、フロートz)の効果は非常に明白で、特にテストデータの後ろに見ることができます。
 
4.luaとC#の間を通過するパラメータ、戻り、次のタイプに合格しないようにしてください。
 
重度のカテゴリ:のVector3 /クォータニオンユニティ値型のように、配列
あまり深刻カテゴリ:ブール文字列の各種オブジェクト
通過をオススメ:int型のダブルフロート
 
LUAとC#は、上院を通過し、多くのデータ・タイプにLUA、C、C#の原因表現、(実現CすべてLUA自体後の)Cの層と、実際に中間この観点、LUAとC#質量参加からもののそして、メモリ割り当て方式が異なっているので、3間のデータ転送は、しばしば、異なるタイプに応じて消費の変換は広く変動(用語パラメータmashalling)に変換する必要があります。
 
私はCとC#のインタラクティブパフォーマンスの消費を伴う、あまり深刻クラスブール文字列型についてお話しましょう、処理のデータ型にMicrosoftの公式ドキュメントによると、C#はBOOLや文字列が非に属するblittable型タイプと非blittable型タイプを、定義されました彼らは、Cに存在し、C#は同じではありません表し、それは必要なときに、CからC#の型変換に渡すことを意味していることを意味-Blittableタイプは、パフォーマンスが低下するだけでなく、マネージヒープメモリに文字列をコピーし、文字列のメモリ割り当てを(考えますそしてUTF8とUTF16システムの変換)。
 
https://msdn.microsoft.com/zh-cn/library/ms998551.aspxを参照することができ、ここではCとC#の最適化ガイドラインの相互作用のパフォーマンスに関する詳細があります。
そして深刻なカテゴリ、原因のC#にオブジェクトに対応するオブジェクトの基本的ウルアプログラムこのような試みのLuaのボトルネック。
消費のするVector3同等のタイプは、既に述べたようにされて。
アレイは、アレイ、場合関連するオブジェクト/列、等からC#の変換のコピーのみluatable基準としてアレイLuaのテーブルのみを発現させることができるので、さらに悪いことであり、全く異なっているC#の、直接的な相関関係が存在しないので、 、それは一つ一つを変換することです。
 
機能の数、パラメータを制御することは、頻繁に呼び出さ
 
それはLuaのpushint / checkintであるかどうか、またはC#のパスをパラメータにC、パラメータ変換は、パラメータの種類と、だけでなく、パラメータに関連付けられているに加えて、最も重要な消費であり、一つのパラメータによって行われ、そのため、LUAコールC#のパフォーマンス素晴らしい関係の数。一般的には、四つのパラメータ、および頻繁にダース以上の引数よりも頻繁ではないと呼ばれる機能は、頻繁に呼び出された場合、あなたは1つがあなたが10msのを見ることができ、電話で何百回も呼び出すことができ、非常に重要な性能低下が表示されますレベル時間。
 
前記優先順位は、静的エクスポート機能を使用するExportメソッドのメンバーの使用を減らします
 
先に述べたように、アクセス方法やメンバ変数へのメンバオブジェクトは、我々は多くを消費し、LuaのユーザデータとC#のオブジェクト参照を見つけるか、メタテーブルを見つける必要があります。直接輸出静的関数は、そのような消費を減らすことができます。
 
像= POS obj.transform.position。
私たちのお勧めのアプローチは似て、静的エクスポート機能として書かれています
クラスLuaUtil { 
  静的ボイドSetPos(ゲームオブジェクトのOBJ、フロートX、フロートY、Z FLOAT){obj.transform.position =新規のVector3(X、Y、Z)。} 
}
 
そして、LuaUtil.SetPosでLUA(OBJ、pos.x、pos.y、pos.z)、このパフォーマンスは頻繁にする必要性を排除することはリターンを変換するので、非常に良くなりますが、また、多くの場合、一時的な戻りLUAを引き起こす変換避けるために、 GC。
 
C#のC#のオブジェクトを参照して保持7.注LUAは、オブジェクトがメモリリークの一般的な原因である、解放することができない原因になります
 
バックLUAに早く、C#のオブジェクト述べたように、ユーザデータのLUAとC#の仲間によってオブジェクトディクショナリである限り、Luaのユーザデータが回復していないとして、C#のオブジェクトは、この辞書への参照を保持されますが、原因が回復することはできません。
 
あなたは、破壊した場合でも、その中のLUA参照は、また、彼らはまだモノラル山に残ったことが判明した場合、最も一般的なのは、ゲームオブジェクトとコンポーネントです。
 
しかし、辞書をC#でのみ関連のLUAあるので、この問題を認識しているため、この辞書について横断することを見つけることは非常に簡単ですが、難しいことではありません。このカテゴリ辞書でウルアObjectTranslator、ObjectCacheでsluaクラス
 
8.オブジェクトのC#を直接参照することなく、Luaの唯一独自の管理IDを用いて検討
 
LuaはC#のへの参照を避けたいです
 
様々なパフォーマンスが一つの方法は、エクスポート機能は、もはや関連の引数として渡されたC#のオブジェクトが、パスのint型である一方、オブジェクトIDは、インデックスオブジェクトに自分自身を持っていない割り当てることです発行します。
 
これにはいくつかの利点をもたらします:
  1. この関数は、より良い性能を呼び出します。
  2. 明示的にオブジェクトのライフサイクルを管理し、不正にLUAでこれらのオブジェクトを参照する場合、オブジェクトが解放することができない原因になります、これらのオブジェクト参照を管理し、自動的にウルアを避けるため、メモリリークするように
  3. C#のオブジェクトは、LUAへの参照がない場合、それは簡単にすぐにGC、およびオブジェクト参照にObjectTranslatorを削除します、LUAに戻りました。この自己参照管理関係は、GCの挙動や分布の挙動が頻繁に発生していません。
例えば、上記LuaUtil.SetPos(ゲームオブジェクトOBJ、フロートX、フロートyは、floatz)さらにLuaUtil.SetPos(INT OBJID、フロートX、フワッ、floatz)を最適化することができます。その後、我々は可能な場合は、むしろ辞書を記録するために、配列を使用するよりも、そして速く検索効率があるだろう、内部の独自のコードでゲームオブジェクトとOBJIDとの対応を記録します。だから、ダウン、さらに時間LUAコールのC#を保存し、オブジェクトの管理がより効率的になります。
 
9.キーワードの使用の合理化は、複雑な戻り値を返します
 
質量参加だけでなく、消費の様々なC#の同様のものでLUAに戻るの様々なタイプ。
 
例えばするVector3 GetPosも(ゲームオブジェクトのOBJ)(floatzうち、フロートYうち、フロートXアウトゲームオブジェクトOBJ)ボイドGetPosものように書くことができます。
 
、生成されたコードに応じて(我々のウルア対象)が導かれるであろう外表面上のパラメータの数を増加させるが、から:LuaDLL.tolua_getfloat3(get_field + TONUMBER 3回を含有する)ISNUMBER + TONUMBER 3倍になります
 
get_fieldにそうそうするために、基本的にISNUMBERアクセスよりも確かに遅いテーブルルックアップ、スタックでより良い性能を持っています。
 
測定
 
まあ、私はここでの時間の最初の部分がありますので、純粋な言語自体を見るために、より現実的な消費するために、我々は直接、gameobj.transform.positionの例を使用していない、データの視点があまりにも曖昧で得ることはありません、そんなに言いました廃棄物の内部結束インチ
 
私たちは、GameObject2とTransform2の簡易版を書き直しました。
クラスTransform2 { 
  公共のVector3位置=新規のVector3()。
} 
クラスGameObject2 { 
   公共Transform2は=新しいTransform2を(変換)。
}
 
その後、我々は、トランスフォームセットの位置を呼び出すには、いくつかの異なる方法を使用します
方式1:gameobject.transform.position = Vector3.New(1,2,3)
モード2:ゲームオブジェクト:SetPos(Vector3.New(1,2,3))
モード3:ゲームオブジェクト:SetPos2(1,2,3)
方式4:GOUtil.SetPos(ゲームオブジェクト、Vector3.New(1,2,3))
方式5:GOUtil.SetPos2(gameobjectid、Vector3.New(1,2,3))
方法6:GOUtil.SetPos3(gameobjectid、1,2,3)
 
1,000,000、luajitアーキテクチャ、il2cpp干渉及び他の要因が異なっているが、我々はさらに意志この次のため、それぞれ、以下の結果(テスト環境は、Windows版であり、CPUはi7-4770で、JITモードオフのluajitは、電話であろう)手の込んだ:
 
モード1:903ms
モード2:539ms
モード3:343ms
モード4:559ms
モード5:470ms
ウェイ6:304ms
 
私たちは、それぞれの最適化、大幅に、特にすべて削除増加を見ることができます。変換および取得するVector3変換アップグレードは巨大で、私たちは外国の輸出の方法を変更し、時間の66%を保存することができるだろう、高いコストを支払う必要はありません。
 
実際には、我々はさらに行くことができませんか?また!途中で6に基づき、我々はそれだけでは200msを行うことができます!
 
ここでは秘密、我々はさらに説明し、次luajit統合。一般的には、私たちのやり方のレベルが6で十分ですお勧めします。
 
これはちょうど、最も単純なケースの一つであり、多くの一般的に使用される輸出の種類があり、私たちは自分の用途に応じて最適化する必要がある(例えばGetComponentsInChildrenこのパフォーマンスピット、またはパラメータの機能は、より多くのダース例よりも渡される)があります私たちは分析の後ろに提供する統合ソリューションのLuaのパフォーマンスの原則は、あなたがそれを行うことは容易である方法を検討する必要があります。
 
次は、ユニティLUA +パフォーマンスの最適化、luajitインテグレーテッド・パフォーマンス・ピットの第二の部分を書きます
 
コードの最初の部分に比べてこれはおそらく消費の問題を知って輸出実績を見ることができるようになり、luajit統合問題ははるかに複雑あいまいです。
 
試験に取り付けられたC#コード:
パブリッククラスTransform2 
{ 
    公共のVector3位置=新規のVector3()。
} 
publicクラスGameObject2 
{ 
    公共Transform2は=新しいTransform2を(変換)。
    公共ボイドSetPos(するVector3 POS)
    { 
        transform.position = POS。
    } 
    公共ボイドSetPos2(フロートxは、Zフロート、Yフロート)
    { 
        transform.position.x = X。
        transform.position.y = Y。
        transform.position.z = Z。
    } 
} 
publicクラスGOUtil 
{ 
    プライベート静的リスト<GameObject2> mObjs =新しいリスト<GameObject2>(); 
    パブリック静的GameObject2 GetByID(int型のID) 
    {
        IF(mObjs.Count == 0)
        { 
            ため(INT I = 0、I 1000 <; iは++)
            { 
                mObjs.Add(新しいGameObject2())。
            } 
        } 
        mObjs [ID]を返します。
    } 
    パブリック静的ボイドSetPos(GameObject2行く、するVector3 POS)
    { 
        go.transform.position = POS。
    } 
    パブリック静的ボイドSetPos2(int型のID、のVector3 POS)
    { 
        mObjs [ID] .transform.position = POS。
    } 
    パブリック静的ボイドSetPos3(INT番号、フロートX、Yフロート、フロートZ)
    { 
        VAR T = mObjs [ID] .transform。
        t.position.x = X。
        t.position.y = Y。
        t.position.z = Z。
    } 
}
します。https://blog.csdn.net/haihsl123456789/article/details/54017522/

おすすめ

転載: www.cnblogs.com/scoregao/p/10984190.html