はじめに
こんにちは、九島茶にゃです。
今回の記事は開発者向けになります。
ILかアセンブリ言語についての知識があるといいでしょう。
Debug/Releaseの違い
簡単に言えば、以下のコードがあったとします。
class Sample {
static void Main() {
int a = 10 * 5;
System.Console.WriteLine(a);
}
}
次に、Sample.cs
と全く同じ動作をする、以下の様なコードがあるとします。
class Sample {
static void Main() {
System.Console.WriteLine(50);
}
}
もしコードに対し逐次的に処理が行われる(コンパイラ、仮想マシン、CPU等での改変がない)としたら、明らかに10 * 5
の計算や変数a
へのstore/load
を行っていないImprovedSample.cs
の方が速いに決まっていますよね?
ちなみに、Sample.cs
をDebug/Releaseでコンパイルするとこう解釈されます。(処理の部分のみ抽出します。assembly等の属性の付加も見たい人はこちら)
- Debugコンパイル
using System;
internal class Sample
{
private static void Main()
{
int value = 50;
Console.WriteLine(value);
}
}
- Releaseコンパイル
using System;
internal class Sample
{
private static void Main()
{
Console.WriteLine(50);
}
}
以上のコードを見ると、Debugでは領域が確保され、代入の処理が行われるのに対し、Releaseでは領域が確保されず、WriteLine
メソッドに直接値が渡されている(不要な処理が省かれている)事がわかります。そのため、Releaseでは一部ブレークポイントをつけても認識されない所があります。ただし、不要な処理が省かれるので明らかに速いです。
IL的な相違
一般的に、Debug/Releaseには最大スタック数(サイズ)、ローカル変数のサイズ、コードサイズにて以下のような関係性があります。
Debug・Releaseにおけるサイズの関係性
- 最大スタック数
- Debug ≦ Release (Debug < Release のとき Release = 8)
- ローカル変数のサイズ
- Debug ≧ Release
- コードサイズ
- Debug > Release
関係性の理由
最大スタック数は基本的に同じです(1,2か引数の数だけ確保される)。しかし、ローカル変数を用いないときはデフォルトのサイズ(8 Bytes)が確保されるので、以上のようになります。
ローカル変数はReleaseSample.cs
の通り、最適化によって領域が確保されない可能性があるからです。
コードサイズは、DebugコンパイラはDebugSample.cs
のようにコードを逐次的にILに変換し、(ブレークポイントのため?)nop
をいくつか追加します。Releaseコンパイラは出来るだけ軽く、短いコードを生成します。勿論、基本的にnop
は生成しません。そのため、以上のようにDebugの方がコードサイズが大きくなります。