Udostępnij za pośrednictwem


Ułatwianie debugowania obrazu na platformie .NET

Uwaga

Ten artykuł jest specyficzny dla programu .NET Framework. Nie ma zastosowania do nowszych implementacji platformy .NET, w tym .NET 6 i nowszych wersji.

Podczas kompilowania niezarządzanego kodu można za pomocą odpowiednich przełączników środowiska IDE lub opcji wiersza polecenia skonfigurować wykonywalny obraz na potrzeby debugowania. Na przykład możesz użyć opcji wiersza polecenia /Zi w programie Visual C++, aby poprosić go o emitowanie plików symboli debugowania (rozszerzenie pliku .pdb). Podobnie opcja /Od wiersza polecenia informuje kompilator o wyłączeniu optymalizacji. Wynikowy kod działa wolniej, ale łatwiej jest debugować, jeśli jest to konieczne.

Podczas kompilowania kodu zarządzanego programu .NET Framework kompilatory, takie jak Visual C++, Visual Basic i C# skompilują swój program źródłowy do wspólnego języka pośredniego (CIL). Funkcja CIL jest następnie kompilowana w trybie JIT, tuż przed wykonaniem, do natywnego kodu maszyny. Podobnie jak w przypadku kodu niezarządzanego za pomocą odpowiednich przełączników środowiska IDE lub opcji wiersza polecenia można na potrzeby debugowania skonfigurować wykonywalny obraz. Można również skonfigurować kompilację JIT na potrzeby debugowania w taki sam sposób.

Taka konfiguracja JIT ma dwa aspekty:

  • Aby wygenerować informacje śledzenia, możesz zażądać kompilatora JIT. Dzięki temu debuger może dopasować łańcuch CIL ze swoim odpowiednikiem kodu maszynowego oraz śledzić lokalizację przechowywania zmiennych lokalnych i argumentów funkcji. W programie .NET Framework w wersji 2.0 lub nowszej kompilator JIT zawsze generuje informacje śledzenia, więc nie ma potrzeby żądania.

  • Możesz zażądać kompilatora JIT, aby nie zoptymalizować wynikowego kodu maszynowego.

Zwykle kompilator, który generuje te opcje kompilatora JIT, odpowiednio ustawia te opcje kompilatora JIT na podstawie przełączników IDE lub opcji wiersza polecenia, które określisz, na przykład /Od.

Czasami trzeba zmienić zachowanie kompilatora JIT, tak aby generowany przez niego kod maszynowy był łatwiejszy do debugowania. Na przykład warto wygenerować informacje ze śledzenia kompilatora JIT dla kompilacji detalicznej lub optymalizacji kontrolek. Należy do tego celu użyć pliku inicjującego (.ini).

Jeśli na przykład zestaw, który chcesz debugować, jest wywoływany MyApp.exe, możesz utworzyć plik tekstowy o nazwie MyApp.ini w tym samym folderze co MyApp.exe, który zawiera następujące trzy wiersze:

[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0

Dla każdej opcji można ustawić wartość 0 lub 1. Każda niezdefiniowana opcja domyślnie przyjmuje wartość 0. Ustawienie w opcji GenerateTrackingInfo wartości 1 i w opcji AllowOptimize wartości 0 zapewni najłatwiejsze debugowanie.

Począwszy od programu .NET Framework 2.0, kompilator JIT zawsze generuje informacje śledzenia niezależnie od wartości GenerateTrackingInfoparametru ; jednak AllowOptimize wartość nadal ma wpływ. W przypadku używania Ngen.exe (generatora obrazów natywnych) do wstępnego kompilowania obrazu natywnego bez optymalizacji plik .ini musi znajdować się w folderze AllowOptimize=0 docelowym, gdy Ngen.exe zostanie wykonany. Jeśli zestaw został wstępnie skompilowany bez optymalizacji, musisz usunąć wstępnie skompilowany kod przy użyciu opcji NGen.exe /uninstall przed ponownym uruchomieniem Ngen.exe, aby wstępnie skompilować kod zgodnie z optymalizacją. Jeśli plik .ini nie znajduje się w folderze, domyślnie Ngen.exe prekompiluje kod jako zoptymalizowany.

Klasa System.Diagnostics.DebuggableAttribute kontroluje ustawienia zestawu. DebuggableAttribute zawiera dwa pola, które kontrolują, czy kompilator JIT powinien zoptymalizować i/lub wygenerować informacje śledzenia. W programie .NET Framework 2.0 i nowszych wersjach kompilator JIT zawsze generuje informacje śledzenia.

W przypadku kompilacji detalicznej kompilatory nie ustawiają żadnych atrybutów DebuggableAttribute. Domyślnie kompilator JIT generuje najwyższą wydajność, najtrudniejszą do debugowania kodu maszyny. Włączenie funkcji śledzenia w kompilatorze JIT obniża wydajność nieznacznie, natomiast wyłączenie optymalizacji zmniejsza ją wyraźnie.

Atrybut DebuggableAttribute ma zastosowanie do całego zestawu jednocześnie, a nie do poszczególnych modułów w zestawie. Narzędzia programistyczne muszą zatem dołączać atrybuty niestandardowe do tokenu metadanych zestawu, jeśli zestaw został już utworzony, lub do klasy o nazwie System.Runtime.CompilerServices.AssemblyAttributesGoHere. Następnie narzędzie ALink promuje te atrybuty DebuggableAttribute z każdego modułu do zestawu, które stają się częścią. Jeśli wystąpi konflikt, operacja ALink zakończy się niepowodzeniem.

Uwaga

W wersji 1.0 programu .NET Framework kompilator Programu Microsoft Visual C++ dodaje atrybut DebuggableAttribute po określeniu opcji kompilatora /clr i /Zi . W wersji 1.1 programu .NET Framework należy ręcznie dodać element DebuggableAttribute w kodzie lub użyć opcji konsolidatora /ASSEMBLYDEBUG .

Zobacz też