아카이빙/C#

[Effective C#] 불필요한 객체를 만들지 말라

셩님 2018. 8. 11. 20:46

[Effective C#] 불필요한 객체를 만들지 말라

  • 가비지 콜렉터는 사용자를 대신하여 메모리를 관리하며 사용하지 않는 객체를 효율적인 방식으로 제거한다

  • 그러나 이 작업이 아무리 효율적이더라도 새로운 객체를 생성하고 삭제하는 일은 그렇지 않은 일에 비해 상대적으로 많은 프로세스 시간을 잡아 먹는다

  • 따라서 가비지 콜렉터가 과도하게 동작하지 않도록 주의해야 함.

1. 자주 사용되는 지역변수를 멤버 변수로 변경

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpriteSetting : System.IDisposable
{
   Vector3 position;
   Color color;
   bool flipX;
   bool flipY;

   public SpriteSetting (Vector3 position, Color color, bool flipX, bool flipY)
  {
       this.position = position;
       this.color = color;
       this.flipX = flipX;
       this.flipY = flipY;
  }

   public void Dispose ()
  {
       throw new System.NotImplementedException ();
  }

   public override string ToString ()
  {
       return string.Format ("[SpriteSetting] : {0}, {1}", this.position, this.color);
  }
}

public class GarbageCollectTest : MonoBehaviour {
   void Update () {
           using (SpriteSetting spriteSetting
          = new SpriteSetting(Vector3.zero, Color.red, true, false))
          {
               Debug.Log (spriteSetting);
          }
}
}
  • 실제로 이런 코드를 사용할 일은 없겠지만, 위의 예제에서는 Update 메소드가 호출될 때마다 동일한 SpriteSetting 객체를 계속 생성한다.

  • 가비지콜렉터의 콜렉팅 작업이 수행될 가능성이 높아지고, 호출 주기가 잦으므로 이러한 코드는 상당히 비효율적이다.

  • 이 경우에는 SpriteSetting 객체를 지역변수로 선언할 것이 아니라 변수로 변경하여 객체를 한 번만 생성한 후 이를 재활용할 수 있도록 개선한다.

public class GarbageCollectTest : MonoBehaviour {
   SpriteSetting spriteSetting
       = new SpriteSetting (Vector3.zero, Color.red, true, false);
   
   void Update () {
       Debug.Log (this.spriteSetting);
}
}

2. 종속성 삽입을 활용해 자주 사용되는 객체를 재활용

private static SpriteSetting mySetting;
public static SpriteSetting FavoriteSpriteSetting
{
   get
  {
       if (mySetting == null)
      {
           mySetting = new SpriteSetting (Vector3.zero, Color.red, true, false);
      }
       return mySetting;
  }
}
  • 이 코드를 보면 FavoriteSpriteSetting을 최초로 요청했을 때 해당 객체를 생성한다.

  • SpriteSetting 클래스에서는 이렇게 생성된 객체를 저장해두고 동일한 요청이 있을 때 마다 이 객체를 돌려 준다.

  • 객체의 수를 최소한으로 유지하기 위해 객체 생성을 제한하는 방법이다.

  • 생성된 객체가 메모리상에 필요 이상으로 오래 남아 있을 수 있다는 단점은 있다.

3. Immutable 타입을 주의

  • 변경불가능한 타입(Immutable)의 대표적인 예로는 System.String이 있다.

  • string 객체가 생성되면 객체가 갖고 있는 문자열의 내용은 변경이 불가능하다.

  • 실제로 프로그래밍을 하다보면 문자열의 내용을 변경할 수 있는 것 처럼 보이지만, 새로운 문자열을 가진 string 객체가 생성되는 것이고, 이전 객체는 가비지가 된다.

void Start()
{
  string msg = "Hello, ":
  msg += "My name is ";
  msg += "Debug-Log";
}
  • 앞선 코드는 실제로는 다음과 같은 비효율적인 방법으로 작업이 이루어진다.

string msg = "Hello, ";

string tmp1 = msg + "My name is "; // new string instance
msg = tmp1;

string tmp2 = msg + "Debug-Log"; // new string instance
msg = tmp2;
  • 따라서 string.format이나 StringBuilder를 통해 객체 생성을 최소화 하자.

References

  • 빌 와그너 (2017), Effective C# (3rd Edition), 한빛미디어