Unclear behavior by Garbage Collector while collecting instance properties or fields of reachable object

后端 未结 1 639
鱼传尺愫
鱼传尺愫 2021-01-14 20:31

Till today I was thinking that members of reachable objects are also considered to be reachable.

But, today I found one behavior which crea

相关标签:
1条回答
  • 2021-01-14 21:17

    However strange this would sound, JIT is able to treat an object as unreachable even if the object's instance method is being executed - including constructors.

    An example would be the following code:

    static void Main(string[] args)
    {
       SomeClass sc = new SomeClass() { Field = new Random().Next() };
       sc.DoSomethingElse();
    }
    class SomeClass
    {
       public int Field;
       public void DoSomethingElse()
       {
          Console.WriteLine(this.Field.ToString());
          // LINE 2: further code, possibly triggering GC
          Console.WriteLine("Am I dead?");
       }
       ~SomeClass()
       {
          Console.WriteLine("Killing...");
       }
    }
    

    that may print:

    615323
    Killing...
    Am I dead?
    

    This is because of inlining and Eager Root Collection technique - DoSomethingElse method do not use any SomeClass fields, so SomeClass instance is no longer needed after LINE 2.

    This happens to code in your constructor. After // ... Pass it to unmanaged library line your Demo instance becomes unreachable, thus its field myDelWithMethod. This answers the first question.

    The case of empty lamba expression is different because in such case this lambda is cached in a static field, always reachable:

    public class Demo
    {
        [Serializable]
        [CompilerGenerated]
        private sealed class <>c
        {
            public static readonly <>c <>9 = new <>c();
            public static Action <>9__1_0;
            internal void <.ctor>b__1_0()
            {
            }
        }
    
        public Action myDelWithMethod;
        public Demo()
        {
            myDelWithMethod = (<>c.<>9__1_0 ?? (<>c.<>9__1_0 = new Action(<>c.<>9.<.ctor>b__1_0)));
        }
    }
    

    Regarding recommended ways in such scenarios, you need to make sure Demo has lifetime long enough to cover all unmanaged code execution. This really depends on your code architecture. You may make Demo static, or use it in a controlled scope related to the unmanaged code scope. It really depends.

    0 讨论(0)
提交回复
热议问题