Beforefieldinit resolution (zz)

Source: Internet
Author: User
Let's not talk nonsense. Let's look at a piece of code first:

View plaincopy to clipboardprint?

  1. Using System;
  2. Using System. Collections. Generic;
  3. Using System. Linq;
  4. Using System. Text;
  5. Namespace BeforeIniField
  6. {
  7. Class Program
  8. {
  9. Class TestStatic
  10. {
  11. Public static string instance = GetString ("Initialize the static field ");
  12. Public static string getstring (string S)
  13. {
  14. Console. writeline (s );
  15. Return S;
  16. }
  17. Static teststatic () {}// note that the static constructor is used here.
  18. }
  19. Static void Main (string [] args)
  20. {
  21. Console. WriteLine ("Start main ");
  22. TestStatic. GetString ("Manually invoke the static GetString () method! ");
  23. }
  24. }
  25. }

Using System; using System. collections. generic; using System. linq; using System. text; namespace BeforeIniField {class Program {class TestStatic {public static string instance = GetString ("Initialize the static field"); public static string GetString (string s) {Console. writeLine (s); return s;} static TestStatic () {}// note that static constructor} static void Main (string [] args) {Console. writeLine ("Start main "); TestStatic. GetString (" Manually invoke the static GetString () method! ");}}}

First, please predict the running result of the program. Well, it should be to print out three strings in the order of start main, initialize the static ......, Manually invoke ...... The answer is correct.

Second, change static teststatic () {} To teststatic (). Does the running result change?

The answer is that there is no change in the debug status. See the following operation:

But the release status changes:

Then, let's add some material to the program: modify the code in the main function as follows:

Console. writeline ("START main ");

Teststatic. getstring ("manually invoke the static getstring () method! ");

String instance = teststatic. instance; // This line is the added code

After the modification, the program running results are consistent in debug and release modes, as shown below:

The question is, why? Note that initialize the static field is printed before start main, indicating that CLR calls the teststatic class constructor in advance (the constructors will initialize member variables one by one, including static member variables, print the initialize the static ......) (You will find that this sentence is not accurate here !). In the program at the beginning, the static constructor of the teststatic class is initialized only before the first access to the static member variable of teststatic. Why is there such a difference?

To better illustrate this question, I would like to provide a piece of lonely code:

View plaincopy to clipboardprint?

  1. Using System;
  2. Using System. Collections. Generic;
  3. Using System. Linq;
  4. Using System. Text;
  5. Using System. Diagnostics;
  6. Namespace BeforeIniField
  7. {
  8. Class TestStatic
  9. {
  10. Public static string instance = "Hello world ";
  11. Public static string GetString (string s)
  12. {
  13. Console. WriteLine (s );
  14. Return s;
  15. }
  16. Static TestStatic ()
  17. {
  18. }
  19. }
  20. Class Test
  21. {
  22. Public static string instance = "Hello world ";
  23. Public static string GetString (string s)
  24. {
  25. Console. writeline (s );
  26. Return S;
  27. }
  28. Test ()
  29. {
  30. }
  31. }
  32. Class Program
  33. {
  34. Private Static void timestatic ()
  35. {
  36. Stopwatch sw = Stopwatch. StartNew ();
  37. For (int I = 0; I <Int32.MaxValue-1; ++ I)
  38. {
  39. String msg = TestStatic. instance;
  40. }
  41. Sw. Stop ();
  42. Console. WriteLine (sw. ElapsedMilliseconds );
  43. }
  44. Private static void Time ()
  45. {
  46. Stopwatch sw = Stopwatch. StartNew ();
  47. For (int I = 0; I <Int32.MaxValue-1; ++ I)
  48. {
  49. String msg = Test. instance;
  50. }
  51. Sw. Stop ();
  52. Console. WriteLine (sw. ElapsedMilliseconds );
  53. }
  54. Static void Main (string [] args)
  55. {
  56. TimeStatic ();
  57. Time ();
  58. }
  59. }

Using system; using system. collections. generic; using system. LINQ; using system. text; using system. diagnostics; namespace beforeinifield {class teststatic {public static string instance = "Hello World"; public static string getstring (string s) {console. writeline (s); Return s;} static teststatic () {}} class test {public static string instance = "Hello World"; public static string getstring (string s) {console. writeline (s); Return s;} test () {}} class program {Private Static void timestatic () {stopwatch Sw = stopwatch. startnew (); For (INT I = 0; I <int32.maxvalue-1; ++ I) {string MSG = teststatic. instance;} SW. stop (); console. writeline (SW. elapsedmilliseconds);} Private Static void time () {stopwatch Sw = stopwatch. startnew (); For (INT I = 0; I <int32.maxvalue-1; ++ I) {string MSG = test. instance;} SW. stop (); console. writeline (SW. elapsedmilliseconds);} static void main (string [] ARGs) {timestatic (); time ();}}

Note that when the static constructor is not declared, the execution time is only half of the declared static constructor. It doesn't matter if I feel confused. I will explain it one by one.

First, take out the fuse weapon under. net, il dissembler, a disassembly program provided by Microsoft. For example:

Note beforefieldinit, which is marked in blue. Note that the C # compiler for the test class also declares a static constructor. The only difference is the beforefieldinit mark, what exactly is this?

First, we need to know that in. net, the initialization process of a class is carried out in the constructor. According to the type of the constructor, the constructor (. cctor) and object constructor (. the difference between the two is that (. ctor) during type instantiation, the corresponding constructor will be executed to initialize the type. cctor is used to initialize static members .. Cctor cannot be called directly. In fact, it is also private because the type constructors are private and users cannot explicitly call the type constructors. Therefore, the execution time of the Type constructor mainly includes two methods in. Net:

Beforefieldinit Method

Precise Mode

The method used depends on whether an explicit static constructor is implemented for the type. If an explicit static constructor is implemented, the precise method is used; if an explicit static constructor is not implemented, it is executed in beforefieldinit mode.
The following is the original explanation of beforefieldinit and precise in section 8.9.5: "the CLI specification (ECMA 335) states in section 8.9.5:

1. A type may have a type-initializer method, or not. (John Note: Obviously, both the test class and the teststatic class have a Type constructor)

2. A type may be specified as having a relaxed semantic for its type-initializer method (for convenience below, we call this relaxed semantic beforefieldinit)

3. if marked beforefieldinit then the type's initializer method is executed at, or sometime before, first access to any static field defined for that type (after beforefieldinit is specified, the call time of the class constructor is weighed by CLR)

4. if not marked beforefieldinit then that type's initializer method is executed at (I. e., is triggered ):

O first access to any static or instance field of that type, or

O first invocation of any static, instance or virtual method of that type

From the specification of CLR, we can make a summary of the role of beforefieldinit. In beforefildinit mode, CLR has the permission to dynamically schedule the execution time of the Type constructor, beforefieldinit provides CLR with the ability to execute at any time. for cctor authorization, you only need to execute this method before accessing the static fields of the type for the first time, emphasizing the performance. The precise method is a latency calling mechanism. For example, beforefieldinit may call a Type constructor in advance, the precise mode does not call the Type constructor until it is used.

Well, let's go back to the Comparison Program. Why is the execution efficiency low after the static constructor is declared? I found the following clues from a blog post:

In actual cases, you won't actually require full laziness-unless your class initialization does something particle ly time-consuming, or has some side-effect elsewhere,It's probably fine to leave out the explicit static constructor shown above. this can increase performance as it allows the JIT compiler to make a single check (for instance at the start of a method) to ensure that the type has been initialized, And then assume it from then on.
This blog post indicates that if the display static Constructor (beforefieldinit) mode is not used, the JIT compiler only needs to check whether the type has been initialized once. In my understanding, that is to say, if the display Constructor (in precise mode) is declared, JIT checks that the Type constructor has been initialized every time, obviously, beforefieldinit is more efficient!

The full text is complete.

References: Wang Tao, what you must know. net

Csdn artech proprietary http://blog.csdn.net/artech

Baidu, google.com inEnglish

Postscript: I wrote this article because I happened to encounter this problem when I was reading the singleton model. I felt very interesting. I just collected some materials online and wrote it as this.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.