GCは効率的に動作するが、それでも無駄なオブジェクトを作りすぎるとパフォーマンス上の悪影響が発生する。
全ての参照型は、ローカル変数であってもメモリ割り当てが行われる。
たとえば、以下のOnPaint
メソッドは、PaintイベントのたびにFont
のオブジェクトが生成されるため、効率が悪い。
protected override void OnPaint(PaintEventArgs e)
{
using (Font MyFont = new Font("Arial", 10.0f))
{
e.Graphics.DrawString(DateTime.Now.ToString(),
MyFont, Brushes.Black, new PointF(0, 0));
}
base.OnPaint(e);
}
以下のように、インスタンス変数にFont
オブジェクトを保持すべきである。
private readonly Font myFont = new Font("Arial", 10.0F);
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawString(DateTime.Now.ToString(),
myFont, Brushes.Black, new PointF(0, 0));
base.OnPaint(e);
}
一般に、参照型で、頻繁に生成されるローカル変数は、メンバー変数に格上げすべきである。
同様に、頻繁に使用されるインスタンスは、静的プロパティ等の形で取得できるようにすべきである。ここでは、以下のような遅延初期化のテクニックも利用できる。
private static Brush blackBrush;
public static Brush Black
{
get
{
if (blackBrush == null)
blackBrush = new SolidBrush(Color.Black);
return blackBrush;
}
}
最後にもう1つ、イミュータブルな型の変更は避けるべきである。たとえば、C#の文字列はイミュータブルである。文字列に変更を加えると、内部ではSystem.String
の新しいインスタンスが生成されている。
文字列の組み立てには、補間文字列か、StringBuilder
を使用すべきである。
string name = "World";
// (非推奨)+= のたびにインスタンスが作られる
string msg1 = "Hello, ";
msg1 += name;
msg1 += ". Today is ";
msg1 += DateTime.Now.ToString();
// (推奨1)補間文字列の使用
string msg2 = $"Hello {name}. Today is {DateTime.Now.ToString()}";
// (推奨2)StringBuilderの使用
string msg3 = new StringBuilder("Hello, ")
.Append(name)
.Append("Today is ")
.Append(DateTime.Now.ToString())
.ToString();
補間文字列は、文字列が短い場合や、組み立てに際してロジックがほとんど必要ない場合に適している。
StringBuilder
は、文字列が長い場合や、組み立てに際してロジックが必要な場合に適している。