代码之家  ›  专栏  ›  技术社区  ›  Robert MacLean

什么是.NET对象生命周期?

  •  14
  • Robert MacLean  · 技术社区  · 15 年前

    在.NET中,对象的生命周期是什么?

    据我所知:

    1. 已创建对象-已调用构造函数(如果存在)
    2. 使用的方法/属性/字段
    3. 对象已销毁-调用了Dispose(如果存在)
    4. GC在某个时刻调用的析构函数
    9 回复  |  直到 10 年前
        1
  •  19
  •   Sander Rijken    15 年前

    Dispose不会被自动调用;您需要调用它,或者使用一个using块,例如。

    using(Stream s = File.OpenRead(@"c:\temp\somefile.txt"))
        // Do something with s
    

    只有当终结器存在时,它才会被GC调用。拥有一个终结器将导致类在两个步骤中被收集;首先将对象放入终结器队列,然后调用终结器并收集对象。直接收集没有终结器的对象。

    准则是Dispose除去托管和非托管资源,而终结器只清理非托管资源。当Dispose方法释放了非托管资源后,它可以调用gc.SuppressFinalize以避免将对象放置在终结器队列上的时间过长。见 MSDN 以获取正确的处置模式样本。

        2
  •  17
  •   Marc Gravell    15 年前

    就像一个边缘案例…您可以在不使用ctor的情况下创建对象:

    class Foo {  
        public Foo() {
            message += "; ctor";
        }
        string message = "init";
        public string Message { get { return message; } }
    }
    static class Program {
        static void Main() {
            Foo foo = new Foo();
            Console.WriteLine(foo.Message); // "init; ctor"
            Foo bar = (Foo)System.Runtime.Serialization.FormatterServices
                .GetSafeUninitializedObject(typeof(Foo));
            Console.WriteLine(bar.Message); // null
        }
    }
    
        3
  •  6
  •   David Schmitt    15 年前

    以下是我知道的步骤:

    1. 加载程序集
    2. 执行静态初始化程序
    3. “新”呼叫:
      1. 分配内存
      2. 执行非静态初始化程序
      3. 执行构造函数
    4. 实例现在可以使用了
    5. 在对对象的最后一个引用消失后:如果对象没有终结器,则它现在可以进行收集;如果对象 一个终结器,它被放入终结器队列。
    6. (可选)终结器队列中的对象在特殊线程中调用了其终结器;如果应用程序仍然没有对对象的引用,则它现在也可以进行垃圾收集。
    7. 垃圾收集器释放内存

    正如其他人已经指出的那样, Dispose() 必须由用户调用,因为运行时不会对其执行操作。

        4
  •  5
  •   Dmitry Risenberg    15 年前

    Here 是问题的详细描述。首先,运行时不调用Dispose,必须自己调用它。也没有析构函数,只有终结器:如果一个对象重写了一个终结的方法,当应用程序无法再访问该对象时,将调用该方法。在完成过程中,可能会再次访问对象(例如,将对自身的引用存储在全局对象中),因此它返回到模型的步骤2。GC对象中还有一些方法允许用户控制对象的终结。

        5
  •  1
  •   Hans Kesting    15 年前

    关于构造函数的一点:

    每个类都有一个类,因为如果不自己编写代码,编译器将生成一个类。 它所做的第一件事(除非另有规定)是调用其父类型的ctor。

        6
  •  1
  •   Matthew Whited    15 年前

    0)如果对象上存在静态构造函数,则第一次调用它,并创建或引用该类型的对象

        7
  •  1
  •   Theofanis Pantelides    15 年前

    下面是一个示例类,它使用本文中提供的所有信息。我已经花了好几个小时测试了,这对我来说是最好的。

    /*********************************
     * Author:  Theofanis Pantelides *
     *   Date:  23 Jun 2009          *
     *********************************/
    
    using System;
    using System.IO;
    
    public class MyClass : IDisposable
    {
        String oFile;
        Stream oStream;
    
        public MyClass(String _File)
        {
            oStream = File.OpenRead(oFile = _File);
            // Initialize
        }
    
        ~MyClass()
        {
            this.Dispose();
            // Destruct
        }
    
        public void doSomething()
        {
            // do Whatever it is you are trying to do
        }
    
        #region IDisposable Members
    
        /// <summary>
        /// Dispose all resources used by instance of class
        /// and update Garbage Collector information
        /// </summary>
        public void Dispose()
        {
            if (oStream != null)
            {
                oStream.Dispose(); // Dispose using built in functions
                GC.SuppressFinalize(oStream); // No need for Garbage Collector
            }
    
            oStream = null;  // Nullify it.
        }
    
        #endregion
    }
    

    用途:

    using(MyClass mc = new MyClass(@"c:\temp\somefile.txt"))
    {
      mc.doSomething();
    }
    

    您甚至可以使用同一声明两次,因为它在“using”之外不存在。

    using(MyClass mc = new MyClass(@"c:\temp\somefile.txt"))
    {
      mc.doSomething();
    }
    
    using(MyClass mc = new MyClass(@"c:\temp\somefile.txt"))
    {
      mc.doSomething();
    }
    
        8
  •  1
  •   ZombieMich    10 年前

    对象生命周期

    创建对象 你使用 新的 关键字来实例化新对象。

    1. 分配内存块。这个内存块足够容纳对象。(clr处理托管对象的内存分配)
    2. 内存块被转换为对象。对象已初始化。(可以通过实现构造函数来控制此步骤)

    摧毁一个物体 :您使用销毁来回收该对象使用的任何资源。

    1. 对象将被清除;例如,通过释放应用程序使用的任何非托管资源(如文件句柄和数据库连接)来清除。(可以通过实现析构函数来控制此步骤。)
    2. 对象使用的内存将被回收。

    clr处理托管对象使用的内存释放;但是,如果使用非托管对象,则可能需要手动释放这些项使用的内存。

        9
  •  0
  •   Hans Malherbe    15 年前

    在C中,成员初始值设定项在构造函数之前调用,而在VB.NET中,成员初始值设定项在构造函数之后调用。

    运行时不保证调用 Finalize 完全。

    处理和定稿是为了清理 无约束的 仅限资源。尝试通过调用内部成员上的Dispose来清理终结器中的托管资源会给您带来麻烦,因为它们可能已经完成。

    我喜欢保持简单,只需要使用终结器来检测和记录一条讨厌的错误消息,告诉开发人员去修复代码。试着弄清楚做这项工作是否安全 Dispose 本来应该做的是太容易出错,通常不值得花周期。