2016-10-26 6 views
5

リサイクルと再利用の変数が統一された良い練習であるとの記事が見つかりました。だから私はそれを採用しました。 しかし、これは値型変数(整数、ベクトル)に適用されますか?これに代えてはリサイクル値の種類がユニティであることを指摘しています

int x; 
Vector3 v; 
void functionCalledVeryOften(){ 
    x=SomeCalculation(); 
    v=SomeCalc(); 
    //do something with x and v 
} 

void functionCalledVeryOften(){ 
    int x=SomeCalculation(); 
    Vector3 v=SomeCalc(); 
    //do something with x and v 
} 
+0

「値の種類のリサイクル」はありません。フィールドとローカル変数を使用しているだけです。 *変数*は通常、この意味では「リサイクル」されません。通常は、プールされた/リサイクルされる*オブジェクト*です(配分を最小限に抑えるために、やりとりやリソース管理のオーバーヘッドを最小限に抑えるため)。 – user2864740

+0

スタックメモリを節約できます。 –

+0

私は完全に "セーブズ"が正しい言葉であるとは確信していません。 – user2864740

答えて

2

これは、あなたがこのオブジェクトに行いたいものにかなり依存している

私はこれを使用してポイントがあります。

最初の例を挙げると、変数x &にアクセスしたいとします。functionCalledEveryOnceSoOften()この関数は変数を渡すためにオーバーロードを必要とせず、クラス。

2番目の例では、同じことをしたいと思ったら、ファンクションは変数に直接アクセスできないため、に電話する必要があります。

多くの場合、関数がチェーンの中で常に呼び出されるとは限りませんが、関数が別の関数と同じ値を使用する必要があります。これを2番目の例に合わせるには、関数内にifステートメントを追加して、これを除外しなければなりません。

ただし、最初の例では、これらの変数を問題なく使用できます。これはしばしばそうするように勧められている理由の1つです。

第2の例では、変数がヒープではなくスタックに格納されます。これは、メソッドが実行を終了すると破棄されるメソッドの境界内で定義されているためです。したがって、変数のメモリ使用量は本当に問題にはなりません。繰り返される創造と破壊のための小さなオーバーヘッドがあるかもしれませんが、これは重要ではありません。

最初の例では、ヒープに変数を格納します。これは、クラスのスコープ内で定義されているため、クラスと共に破棄され、インスタンス化された上でのみ作成されます。これは、メモリが長期間にわたって使用される可能性があることを意味しますが、変数を作成/破棄するためのオーバーヘッドはありません。これは通常、重要ではありません。

これらのオブジェクトを何千もインスタンス化していない限り、連続して変数にアクセスする場合を除いて、パフォーマンスの違いはほとんど気づかないでしょう。

最も大きな違いは、コードの書き方の可能性が高いことです。良かれ悪しかれ。

+0

バッテリーの使用量や熱がスタック上で繰り返され、変数の作成と破壊が繰り返されるのでしょうか? – ShoulO

+1

@ ShoulO個人的には、aがbを超えて使用されている、またはその逆のプロジェクトで、熱やバッテリーの使用量に違いがないことに気づいていません。実際には、それを最適化することさえ考えても私にはそれほど大きなインパクトはありませんでした。 10回中9回は他の場所にあるより重要な影響と完全なボトルネックがあります –

+1

@ShoulO番号ローカル変数*アクセスが効率的です。さらに、変数が表すオブジェクトは「スタック上」でなくてもよい。フィールドメンバーを使用する目的は、* object *の再利用または共有を許可することです。オブジェクトの再利用は、値型のみを含む値型には適用されません。 – user2864740

5

リサイクル値型の団結のポイントがあります

はい、いくつかのデータ型がすべてではありません。

これは値型の変数(整数、ベクトル)に適用されますか?

いいえ

変数の種類によって異なります。

これははintdoublefloatboolVector3Vector2や他の類似のデータ型には適用されされません。すでにstringはC#で再利用できないため、stringには適用されません。 stringsは不変です。

実際には、ローカル変数からintを使用すると、whileというループは、グローバルとして宣言されたintを使用するよりも高速です。

* を一度と宣言して再利用するか、自分の言葉でUnity *の変数をリサイクルまたは再利用する場合の例。

配列

関数は配列が含まれており、その機能は、多くの場合、呼び出された場合。

void functionCalledVeryOften() 
{ 
    float[] playerLives = new float[5]; //This is bad because it allocates memory each time it is called 
    for (int i = 0; i < playerLives.Length; i++) 
    { 
     playerLives[i] = UnityEngine.Random.Range(0f,5f); 
    } 
} 

これはメモリを毎回割り当てるため、配列全体をグローバルにして関数外で一度初期化することで解決できます。新しいオブジェクトの作成

がリソースを取り、モバイルデバイス上の問題を引き起こす可能性があります:あなたは0

float[] playerLives = new float[5]; 
void functionCalledVeryOften() 
{ 
    for (int i = 0; i < playerLives.Length; i++) 
    { 
     playerLives[i] = UnityEngine.Random.Range(0f,5f); 
    } 
} 

作成新しいオブジェクトに配列内のデータをリセットし、簡単な関数を作成することができます。これはあなたがこれを何回行うかによって異なります。

以下のコードはGameObject(箇条書き)を作成し、Rigidbodyを添付して撮影します。これはスペースバーが押されている間にすべてのフレームで発生し、最終的には弾丸秒を破棄します。それは毎回新しいゲームオブジェクトが作成されたメモリを割り当て、ゲームオブジェクトが破棄されるとき、それはまた、ガベージコレクタをトリガするよう

void functionCalledVeryOften() 
{ 
    if (Input.GetKey(KeyCode.Space)) 
    { 
     //Create new Bullet each time 
     GameObject myObject = new GameObject("bullet"); 
     Rigidbody bullet = myObject.AddComponent<Rigidbody>() as Rigidbody; 
     //Shoot Bullet 
     bullet.velocity = transform.forward * 50; 
     Destroy(myObject); 
    } 
} 

上記のコードは悪いです。これは、あなたのゲームでは、しゃっくりを遅くして、引き起こす可能性があります。

上記のコードの解決策は、オブジェクトプーリングです。あなたはここでそれについての詳細を学ぶことができます。グローバル変数と、このための簡単な修正のObject Pooling tutorial from Unity

例:

List<GameObject> reUsableBullets; 
int toUseIndex = 0; 

void Start() 
{ 
    intitOnce(); 
} 

//Call this function once to create bullets 
void intitOnce() 
{ 
    reUsableBullets = new List<GameObject>(); 

    //Create 20 bullets then store the reference to a global variable for re-usal 
    for (int i = 0; i < 20; i++) 
    { 
     reUsableBullets[i] = new GameObject("bullet"); 
     reUsableBullets[i].AddComponent<Rigidbody>(); 
     reUsableBullets[i].SetActive(false); 
    } 
} 

void functionCalledVeryOften() 
{ 
    if (Input.GetKey(KeyCode.Space)) 
    { 
     //Re-use old bullet 
     reUsableBullets[toUseIndex].SetActive(true); 
     Rigidbody tempRgb = reUsableBullets[toUseIndex].GetComponent<Rigidbody>(); 

     tempRgb.velocity = transform.forward * 50; 
     toUseIndex++; 

     //reset counter 
     if (toUseIndex == reUsableBullets.Count - 1) 
     { 
      toUseIndex = 0; 
     } 
    } 
} 

をゲームが始まる前に、だから、基本的に、あなたが関数内でオブジェクトを作成し、保存しますグローバル変数の参照。その後、その参照がグローバル変数に保持されているので、関数で作成したオブジェクトを再利用します。

インスタンス化

Instantiate関数はプレハブのコピーを作成するために使用されます。 以下のコードは、スペースバーが押されている間に弾丸をインスタンス化し、フレームごとに射撃し、最後にそれを破壊します。10秒。それは弾丸プレハブとどのくらいの子供のゲームオブジェクトがその下にあるに装着されているどのように多くの要素に依存するメモリを割り当てるよう

public GameObject bulletPrefab; 
void functionCalledVeryOften() 
{ 
    if (Input.GetKey(KeyCode.Space)) 
    { 
     //Create new Bullet each time 
     Rigidbody bullet = Instantiate(bulletPrefab, new Vector3(0, 0, 0), Quaternion.identity) as Rigidbody; 
     //Shoot Bullet 
     bullet.velocity = transform.forward * 50; 
     Destroy(myObject,10f); 
    } 
} 

上記のコードは悪いです。このソリューションは、オブジェクトプールも使用しています。関数内のGameObjectをインスタンス化し、参照をグローバル変数に格納してから、それらを再利用します。ソリューションは上記のソリューションと同じです。

結論として、質問のサンプルコードはこのを適用しません。

Unityのメモリ管理の詳細については、hereを参照してください。