Ich glaube, ich beobachte den .NET JIT Compiler, der Aufrufe leerer statischer Methoden, die keine Nebeneffekte haben, nicht einreiht oder optimiert, was angesichts einiger maßgeschneiderter Online-Ressourcen ein wenig überraschend ist.Warum sollte der .NET JIT-Compiler entscheiden, Aufrufe von leeren statischen Methoden, die keine Nebenwirkungen haben, nicht zu inline zu verarbeiten oder zu optimieren?
Meine Umgebung ist Visual Studio 2013 auf x64, Windows 8.1, .NET Framework 4.5.
dieses einfache Testprogramm gegeben (https://ideone.com/2BRCpC)
class Program
{
static void EmptyBody()
{
}
static void Main()
{
EmptyBody();
}
}
Ein Release-Build mit Optimierungen des obigen Programms erzeugt folgende MSIL für Main
und EmptyBody
:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 6 (0x6)
.maxstack 8
IL_0000: call void Program::EmptyBody()
IL_0005: ret
} // end of method Program::Main
.method private hidebysig static void EmptyBody() cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method Program::EmptyBody
Es ist nicht verwunderlich, dass die MSIL enthält einen Aufruf von Main
an EmptyBody
, da erwartet wird, dass der C# -Compiler solche Aufrufe nicht inline oder optimiert. Ich dachte jedoch, dass der JIT-Compiler dann diesen Aufruf inline oder optimieren würde. Aber das scheint nicht zu passieren.
Wenn ich das obige Programm und breche in den Debugger in Main
ausführen, wird die erzeugte Baugruppe dies:
00572621 mov ebp,esp
00572623 cmp dword ptr ds:[4320B84h],0
0057262A je 00572631
0057262C call 73E6AF20
00572631 call dword ptr ds:[4321578h]
Der Befehlszeiger wird sofort bei 00.572.631 bis zur letzten Zeile gesetzt, die der Anruf an EmptyBody
ist . Der Schritt in EmptyBody
wird die generierte Assembly gefunden
00BD2651 mov ebp,esp
00BD2653 cmp dword ptr ds:[4B00B84h],0
00BD265A je 00BD2661
00BD265C call 73E6AF20
00BD2661 nop
00BD2662 pop ebp
00BD2663 ret
Der Befehlszeiger sein wird sofort an die nop
Linie bei 00BD2661, die nichts tun, und ich kann nicht erraten, warum es in erster Linie erzeugt wird.
Da die beiden Assembly-Snippets den gleichen 4-Befehl-Header teilen, gehe ich davon aus, dass es sich nur um die normale Methodeneintrags-Kesseltafel handelt, auf der der Stack und so eingerichtet ist. Ich bin daran interessiert, zu lernen, zu wissen, was diese wiederkehrenden Anweisungen tun würde, aber:
00BD2653 cmp dword ptr ds:[4B00B84h],0
00BD265A je 00BD2661
00BD265C call 73E6AF20
Wie auch immer, die wichtigste Frage ist: Warum funktioniert der JIT-Compiler produzieren Assembly, die die leeren Körper statische Methode EmptyBody
nennt?
Ich bin kein Experte für C#. aber das Beobachten eines Systems ändert es;) Sie sehen den Code möglicherweise vollständig zugunsten Ihres Debuggers. –
Wahr. Dann bin ich neugierig zu wissen, wie man überhaupt wissen kann, ob ein Anruf weg optimiert wurde oder nicht, was einige der "bespokten Online-Ressourcen" behauptet haben :-) –
@JohannGerell Schalten Sie das Debug-Flag aus und kompilieren Sie für die Veröffentlichung Modus, dann fügen Sie einen Debugger zur Laufzeit, das wird sicherstellen, dass Sie den tatsächlichen Code debuggen. Ich glaube nicht, dass der JIT den Debugger überwachen wird, um zu sehen, ob er später angehängt wird, und basierend darauf Änderungen an der ASM vorzunehmen. – rolls