Pytanie pole statyczne Inicjalizacja w kompilacji debugowania i wydania


Odkryłem, że inicjalizacja pola statycznego może działać inaczej. dla następującego kodu,

public class Class1
{
  public static void Main()
  {
    Console.WriteLine("Main");
    Test();
    Console.ReadLine();
  }

  public static void Test(){
    Console.WriteLine("Test");
    Singleton.Instance.DoSomething();
  }
}

public class Singleton
{
  private static Singleton sInstance = new Singleton();

  protected Singleton()
  {
    Console.WriteLine("Singleton Constructor");
  }

  public static Singleton Instance
  {
    get
    {
      return sInstance;
    }
  }

  public void DoSomething(){}
}

w kompilacji debugowania zostanie wydrukowany

Main
Test
Singleton Constructor

podczas kompilacji wydania zostanie wydrukowany

Main
Singleton Constructor
Test

Sprawdziłem kod IL wygenerowany przez te 2 kompilacje, są prawie takie same.

Zastanawiam się, jak to się dzieje? A jeśli jest to rodzaj optymalizacji JIT w kompilacji wydania, jaka jest motywacja?


12
2018-05-27 15:45


pochodzenie


Zobacz także Jon Skeet's Wpisz zmiany inicjalizacyjne w .NET 4.0 artykuł - Michael Liu


Odpowiedzi:


Całkowicie zależy to od implementacji, gdy uruchamiane będą statyczne inicjatory . Tak więc kolejność może być inna. Ale jeśli podasz statyczny konstruktor, te statyczne inicjatory będą zawsze wykonywane wcześniej. W związku z tym wyniki będą w spójnej kolejności.

Od MSDN

Inicjatory zmiennych statycznych klasy odpowiadają sekwencji przydziałów, które są wykonywane w kolejności tekstowej, w jakiej występują w deklaracji klasy. Jeśli w klasie istnieje konstruktor statyczny (Rozdział 10.11), wykonanie inicjalizatorów pól statycznych następuje bezpośrednio przed wykonaniem tego statycznego konstruktora. W przeciwnym razie inicjatory pól statycznych są wykonywane w czasie zależnym od implementacji przed pierwszym użyciem pola statycznego tej klasy.

Dodać konstruktor statyczny w Singleton klasa

static Singleton() { }

5
2018-05-27 15:58





I repro dla jitter x86 w kompilacji wydania. Jest to zgodne z projektem, nie ma zagwarantowanego dokładnego momentu, w którym działa konstruktor klasy statycznej, jedynym wymogiem jest to, że tak się dzieje przed dowolne inne metody w klasie. Optymalizator może więc zmienić kod, jeśli generuje bardziej wydajny kod. Czyni to, przesuwa wywołanie cctora z powrotem do metody Main (). Dzięki tej przewadze ma teraz więcej możliwości zoptymalizowania pozostałego kodu.

Ogólnie rzecz biorąc, chcesz uniknąć pisania kodu w wyrażeniach inicjalizujących, które mają zauważalne efekty uboczne.


1
2018-05-27 16:18



Dziękuję za odpowiedź, zastanawiam się, dlaczego przeniesienie cctora wcześniej mogło uzyskać więcej możliwości optymalizacji? - Fei


W kolejna odpowiedź, Zapewniam program testowy i dyskusję na temat porównania pomiędzy {Debugowanie, Release}, {x86, x64} i .NETTO główne wersje. Podsumowane wyniki są następujące; w celu uzyskania szczegółowych informacji, sprawdź połączyć:

.NET 2.0 / 3.5

2.0.50727.8825 x86 Debug
2.0.50727.8825 x86 Debug TouchMe fieldinit
2.0.50727.8825 x86 Release fieldinit
2.0.50727.8825 x86 Release TouchMe fieldinit
2.0.50727.8825 x64 Debug
2.0.50727.8825 x64 Debug TouchMe fieldinit
2.0.50727.8825 x64 Release
2.0.50727.8825 x64 Release TouchMe fieldinit

.NET 4.7.1

4.7.2556.0 x86 Debug
4.7.2556.0 x86 Debug TouchMe fieldinit
4.7.2556.0 x86 Release
4.7.2556.0 x86 Release TouchMe
4.7.2556.0 x64 Debug
4.7.2556.0 x64 Debug TouchMe fieldinit
4.7.2556.0 x64 Release
4.7.2556.0 x64 Release TouchMe


0
2017-12-22 01:50