リリースバージョン:デバッグはまだ始まったばかりです...
何言ってるの?
プログラムはようやく機能し、顧客は自信を持ってテストサイトでボタンを押します。すべてが通常どおり動作します...しかし、喜んで急いでください:リリースバージョンのリリース後に問題が発生する可能性があります。 ソフトウェアは不可解なバグで溢れ出し始め、顧客はイギリス国旗であなたを引き裂く準備ができています...
これはS-shnikovだけの問題だと思いますか? あなたは間違っています!
実用例
通常、デバッグバージョンをテストサイトに配置することに慣れています(もちろん、これはすべての人に当てはまるわけではありませんが、信じられますが、これは非常に頻繁に起こります)。 これにより時間を節約でき、より多くのデバッグ情報があり、リモートデバッグに巻き込まれる可能性があります...
リリースをリリースすることの負担は、あなたにはほとんど関心がないように思われますが、.NETは少し改善されたC ++
であり、特定の問題があります。 しかし、すべてが最初に見えるほどクラウドレスではありません。
例:
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
-
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
-
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
-
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
-
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
-
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
-
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
-
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
-
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
-
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
static void Main( string [] args) { System.Threading.Timer t = new System.Threading.Timer(state => { Console .WriteLine( "Timer!" ); GC.Collect(); }, null , 0, 1000); Console .ReadKey(); } * This source code was highlighted with Source Code Highlighter .
著者の意図によると、最も単純なコードは、切望されている「タイマー!」を1秒に1回コンソールに書き込むことです。 デバッグ構成で収集されたプロジェクトのデバッグでは、疑わしいものは何も明らかにされず、リリースが準備されています...プログラム
は動作しません 。
デブリーフィング
はい、はい、この「バグ」は最適化の直接的な結果です(そしてもちろん、プログラマーの小さな過失です)。 怠慢は、指定されたSystem.Threading.Timerが実際にIDisposableを継承するという事実にあり、最良の場合、それに対してDispose()メソッドを呼び出す必要があります。 さて、これを行わないようにしましょう(実際、これは無関係です)。
リリースおよびデバッグバージョンで生成されたILコードのリストを調査し、これを確認します。
デバッグ:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 5
.locals init (
[0] class [mscorlib]System.Threading.Timer t)
L_0000: nop
L_0001: ldsfld class
[mscorlib]System.Threading.TimerCallback ConsoleApplication11.Program::CS$<>9__CachedAnonymousMethodDelegate1
....
およびリリース:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8
L_0000: ldsfld class [mscorlib]System.Threading.TimerCallback ConsoleApplication11.Program::CS$<>9__CachedAnonymousMethodDelegate1
....
違いを
強調しました 。
まだ推測していない人のために
デバッグバージョンでは、コンパイラは使用されていない(宣言を除く)Timerリンクをスタックに残し、GCはリンクが(メソッドが終了するまで)生きていることを確認します。 タイマーが実行されています。
このバージョンのリリースでは、リンクはどこにも存在せず、最初の(保証されない)メソッドGC.Collect()はタイマーを破壊します。
あとがき
上記の例のように、実生活で明示的な(またはそうでない)オプティマイザーのバグに出くわすことは決してないことを心から願っています。 このようなバグの検索(特に顧客側)は非常に複雑です。「欠陥」アセンブリとそのさらなる分析を検索するために、すべてのコンポーネントのデバッグバージョンをアセンブルし、リリースで徐々にパーツをコンパイルすることをお勧めします。 デバッグ情報(通常は通常.pdbファイル)の配布も役立ちます。
良い金曜日を過ごして、ログイン8-)
All Articles