Warum bindet C # die lokalen Variablen im Voraus? [geschlossen]

7

In C # haben Sie möglicherweise den folgenden Code:

%Vor%

Sobald Sie DoSomething eingeben, richtet die CLR Platz für int x ein. Warum wartet es nicht, bis es die Zeile mit int x = 5 erreicht? Vor allem, obwohl x gebunden ist, lässt es Sie nicht wirklich verwenden, bis diese Zeile überhaupt erreicht wird?

    
GWLlosa 02.02.2012, 00:14
quelle

4 Antworten

13
  

Sobald Sie DoSomething eingeben, richtet die CLR den Platz für int x ein. Warum wartet es nicht, bis es die Zeile mit int x = 5 erreicht?

Die Frage ist nicht zu beantworten, weil die ganze Frage auf einer falschen Prämisse beruht. Der Speicherplatz für die lokale Variable kann sein:

  • wird zugewiesen, wenn die Methode zum ersten Mal eingegeben wird
  • wird zugewiesen, wenn die Steuerung die Deklaration erreicht
  • wird zugewiesen, wenn die Steuerung die Initialisierung erreicht (vorausgesetzt, Initialisierung und Deklaration sind unterschiedlich)
  • wird unter besonderen Umständen zugewiesen - wenn z. B. der Local ein Closed-over-Local eines Lambda oder in einem Iterator-Block oder in einem Async-Block ist, kann die Art und Weise, wie der lokale Speicher zugewiesen wird, kompliziert werden >
  • ganz weggelassen; Wenn das lokale niemals verwendet wird, wird es möglicherweise nicht an erster Stelle zugewiesen.

Der C # -Compiler und der JIT-Compiler stellen auf jeden Fall sicher, dass der lokale Speicher auf eine Weise zugewiesen wird, die korrekt ist, und versuchen, sicherzustellen, dass er effizient ist. Wie sie dies tun, hängt von der genauen Situation ab. Es könnte effizienter sein, den Speicherplatz im Voraus zuzuweisen, und es ist möglicherweise effizienter, ihn nur so lange zuzuweisen, wie die Variable verwendet wird. Der Jitter ist bei der Wahl der Lebensdauer einer lokalen Variablen mit einer breiten Breite zulässig. Lokale Variablen dürfen länger und kürzer leben als ihre Gültigkeitsbereiche, wenn der Jitter dies ohne Verletzung der Programmkorrektheit tun könnte.

Da die Prämisse der Frage falsch ist, gibt es keine Antwort auf die Frage. Stellen Sie eine bessere Frage.

    
Eric Lippert 02.02.2012, 18:23
quelle
10

Wie Sie vielleicht wissen, gibt es mehrere Schritte vom C # -Code zum nativen Code, die sind:

  • Kompilieren von C # nach IL (Bytecode)
  • JITting von Bytecode zu nativem Code

C # hat keine Kontrolle über die Zeit, wenn Speicher zugewiesen wird, was Sie binding nennen, dies liegt ganz bei JIT. Wenn wir dies aus dem Weg räumen, sehen wir, was in C # ist. Der von C # erzeugte Byte-Code muss dem Standard CLR ECMA entsprechen. Wenn wir zu Abschnitt 12.1.6.1 von Partition 1 gehen, werden wir sehen, dass der Standard definiert, dass die Heimatvariable der lokalen Variable im Methodenkopf ist. Da Methodensignaturen in der Regel am Anfang einer Methode in einer Auflistung angezeigt werden, erhalten Sie eine (falsche) Vorstellung, dass sie im Voraus gebunden sind , was tatsächlich der Fall sein kann oder auch nicht .

Wenn Sie jedoch den kompilierten nativen Code betrachten, kann das Ergebnis von Plattform zu Plattform variieren. Die Zuweisung von Speicherplatz auf dem CPU-Stack für eine lokale Variable erfolgt in der Vergangenheit durch einen einzelnen CPU-Befehl zum Ändern des Stack-Pointers. Wenn Sie es Variable für Variable tun wollen, dann haben Sie viele Anweisungen, einen pro Variable, was weniger effizient ist. Aus diesem Grund werden Sie zumindest auf x86 sehen, dass der Speicherplatz auf dem CPU-Stack im Voraus zugewiesen wird.

    
Andrew Savinykh 02.02.2012 00:40
quelle
3

Was sollte der Compiler tun, wenn er etwas Ähnliches findet wie:

%Vor%

Außerdem denke ich wirklich, dass die Kosten für die Einrichtung von Lokalen kein Faktor sind. Wenn es dann zu tun ist, haben Sie wahrscheinlich viel zu viele Einheimische in einer einzigen Methode und Sie sind besser dran Refactoring Ihres Codes.

    
InBetween 02.02.2012 00:43
quelle
1

Ihre Frage scheint auf einigen Annahmen zu beruhen:

  • Die Kosten für die Einrichtung werden immer hoch sein
  • Setup wird nur ein paar Mal vorkommen
  • Der Referenz- / Werttyp auf der CLR-Ebene weist immer eine Eins-zu-eins-Zuordnung mit der Variablen auf der C # -Ebene
  • auf

Das mag für Ihren Code stimmen, aber möglicherweise nicht für den Großteil des Codes da draußen.

Die Annahmen scheinen auch das Vorhandensein von darunter liegenden Schichten des Prozesses zu ignorieren, die dies bis zum Maschinencode kompilieren / interpretieren.

Kurz gesagt, der Code, den Sie in C # schreiben, ist eine Abstraktion, die auf IL beruht, die eine andere Abstraktion ist, die auf der CLR beruht, die eine andere Abstraktion ist usw.

Für das, was es wert ist, habe ich ernsthafte Zweifel daran, dass diese Entscheidung jemals einen erheblichen Einfluss auf die Leistung Ihrer Anwendung gehabt hat ... aber vielleicht ist das ähnlich wie bei Eric Lippert ( Ссылка ) kann eine ausführlichere Analyse teilen.

    
lzcd 02.02.2012 00:43
quelle

Tags und Links