C # BeforeFieldInit Jon Skeet Erklärung Verwirrung

10

Ich habe Jon Skeets Artikel über beforefieldinit gelesen und bin auf eine Frage gestoßen. Er erwähnt, dass der Typinitialisierer jederzeit aufgerufen werden kann, bevor die erste Referenz auf ein statisches Feld aufgerufen wird.

Dies ist mein Testcode:

%Vor%

Die Ausgabe ist:

%Vor%

Aber ohne die markierte Zeile , also ohne Aufruf des statischen Feldes x1 , lautet die Ausgabe:

%Vor%

Der Aufruf von Objekten , die mit beforefieldinit gekennzeichnet sind, beeinflusst also den Aufruf ihrer Typinitialisierer? Oder gehört das zu dem seltsamen Effekt von beforefieldinit , den er erwähnt hat?

  

Also kann beforefieldinit den Aufruf des Typinitialisierers noch fauler oder eifriger machen.

    
L. Guthardt 21.11.2017, 14:59
quelle

1 Antwort

20

Ich bin nicht sicher, welche Frage hier gestellt wird; vielleicht, wenn ich erkläre, was im Kopf des Jitters vorgeht, wird das die Frage beantworten.

Statische Klassen mit einem expliziten statischen Konstruktor haben eine "strenge" Semantik, wenn der cctor ausgeführt wird: wird sofort vor der ersten Verwendung von ausgeführt ein Mitglied des Typs. Also wenn du

hast %Vor%

dann wird der cctor für Foo NICHT ausgeführt, wenn whatever falsch ist, weil wir noch keine tatsächliche Verwendung eines Mitglieds gefunden haben.

Überlegen Sie, was das für den Jitter-Code bedeuten muss. Wie würden Sie einen Jitter für eine Sprache schreiben, die diese Anforderung erfüllt?

Für statische Methodenaufrufe können Sie an jeder Aufrufstelle ein kleines Prequel setzen, das prüft, ob der cctor ausgeführt wurde. Aber das macht jede Call-Site größer und langsamer.

Sie könnten das Prequel in die statische Methode selbst übernehmen. Das würde die Call-Sites klein halten, aber jeder Anruf würde immer noch etwas langsamer werden.

Oder Sie könnten schlau sein und den Check in den Jitter setzen, wenn die statische Methode zum ersten Mal ausgeführt wird . Auf diese Weise erhalten Sie die Kosten für die Überprüfung nur einmal und die Websites bleiben klein. Die Jit-Kosten werden größer, aber nur um einen winzigen Bruchteil; Jitting ist schon teuer.

Beachten Sie jedoch, dass eine Optimierung verhindert, die dazu führt, dass eine Methode vor ihrem ersten Aufruf jittert wird , da eine solche Optimierung jetzt ein Korrektheitsproblem einführt. Optimierung beinhaltet fast immer Kompromisse!

Aber für Feldzugriffe gibt es keine Methode zum Jit. Der Jitter müsste jedem Zugriff auf das Feld, der möglicherweise der erste sein könnte, ein kleines Prequel vorlegen . Der Zugriff auf ein Feld wird nicht nur langsam, sondern auch groß .

Sie könnten denken, warum nicht das Feld zu einer Eigenschaft machen und das Prequel auf das Jitting von Getter und Setter setzen? , aber das funktioniert nicht, weil Felder Variablen sind und Eigenschaften sind nicht. Wir müssen in der Lage sein, statische Felder beispielsweise über ref und out zu übergeben, aber Sie können dies nicht mit einer Eigenschaft tun. Das Feld könnte volatile sein und keine Eigenschaft sein. Und so weiter.

Es wäre schön, diese Kosten bei Feldzugängen vermeiden zu können.

Statische Klassen ohne einen expliziten cctor, aber mit einem vom Compiler generierten impliziten cctor um die statischen Felder zu initialisieren erhalten eine "entspannte" Semantik wobei der Jitter lediglich garantiert, dass der cctor an irgendeinem Punkt vor einem Feld aufgerufen wird wird zugegriffen. Ihr Programm verwendet diese entspannte Semantik.

In der ersten Version mit einem Feldzugriff weiß der Jitter von seiner Analyse der Methode, auf die auf ein statisches Feld zugegriffen werden kann . (Warum "könnte"? Wie zuvor könnte der Zugriff unter einem if liegen.) Der Jitter darf den cctor bei any Zeit vor dem ersten Zugriff ausführen, also macht er es eine Anmerkung, die sagt, wenn Main jitted ist, überprüfen Sie, ob der Test1 cctor ausgeführt wurde, und wenn nicht, führen Sie es aus .

Wenn Main ein zweites Mal aufgerufen wird, hey, es wird nur einmal gesendet. Auch hier werden die Kosten für den Scheck nur beim ersten Anruf getragen. (Natürlich wird Main nur einmal in den meisten Programmen aufgerufen, aber Sie können ein rekursives Main schreiben, wenn Sie in dieser Sache sind.)

In Ihrem zweiten Programm gibt es keinen Feldzugriff. Der Jitter könnte auch darauf hindeuten, dass auf eine statische Methode zugegriffen wird und dass die cctor zu jit-Zeit für Main ausgeführt werden könnte. Es tut nicht. Warum nicht? Ich weiß es nicht; Sie müssten das Jitter-Team danach fragen. Aber der Punkt ist, dass der Jitter vollständig innerhalb seiner Rechte liegt um eine Heuristik zu verwenden, um zu entscheiden, ob der cctor zum Zeitpunkt jit ausgeführt werden soll oder nicht, und tut es auch .

Der Jitter ist auch innerhalb seiner Rechte, eine Heuristik zu verwenden, um zu entscheiden, ob ein Aufruf einer statischen Methode, die kein Feld berührt, den cctor auslöst oder nicht; in diesem Fall tut es das anscheinend unnötig.

Ihre Frage scheint zu sein: "Was sind diese Heuristiken?" und die Antwort ist ... nun, ich weiß nicht genau, was die Antwort ist, und es ist ein Implementierungsdetail der Laufzeit, das sich nach Belieben ändern kann. Sie haben in dieser Antwort gesehen, was einige gute Vermutungen über die Natur dieser Heuristiken sind:

  • Überprüfen Sie, ob der cctor von T ausgeführt werden muss, wenn eine statische Methode von T jitted ist
  • Überprüfen Sie, ob der cctor von T ausgeführt werden muss, wenn eine Methode, die auf ein statisches Feld von T zugreift, jitted ist

Diese Heuristiken würden die Anforderungen der entspannten Semantik erfüllen und würden es vermeiden, alle Prüfungen an Rufstellen auszugeben, und würden dennoch ein vernünftiges Verhalten sicherstellen.

Aber Sie können sich nicht auf diese Vermutungen verlassen. Alles, worauf Sie sich verlassen können, ist, dass der cctor vor dem ersten Feldzugriff auf einige -Punkte ausgeführt wird, und genau das bekommen Sie.Ob ein Feldzugriff in einer bestimmten Methode vorhanden ist oder nicht, ist offensichtlich ein Teil dieser Heuristik, aber diese Heuristiken könnten sich ändern.

    
Eric Lippert 21.11.2017, 15:35
quelle

Tags und Links