【问题标题】:Exception throw from constructor and what happen to instance and memory allocation?构造函数抛出异常以及实例和内存分配会发生什么?
【发布时间】:2017-04-03 05:13:48
【问题描述】:

我有这样的课。 (这只是例子)

    public class NewTest
    {
        public int I { get; set; }
        public NewTest()
        {                
            I = 10;
            throw new ApplicationException("Not Possible");
        }
    }

现在如果我使用这样的类

 NewTest t = new NewTest();

在上面的行中,作为 NewTest 构造函数抛出异常变量 t 从不分配任何值,因为在构造函数完成之前它会抛出异常,但根据测试和其他问题 (Why throwing exception in constructor results in a null reference?) 对象被创建。

现在这个对象是在堆中创建的,但它没有任何根变量供参考,所以它会为垃圾收集带来问题吗?或者它是什么东西的内存泄漏?


以下示例可帮助我消除困惑。 另一个例子

 namespace ConsoleApplication1
 {
 class Program
 {
    static void Main(string[] args)
    {
        NewMethod();
        System.GC.Collect();
        Console.WriteLine("Completed");
        Console.ReadLine();
    }

    private static void NewMethod()
    {
        Object obj = null;
        try
        {
            Console.WriteLine("Press any key to continue");
            Console.ReadLine();
            NewTest t = new NewTest(out obj);
        }
        catch
        {
            Console.WriteLine("Exception thrown");
        }

        try
        {
            Console.WriteLine("Press any key to continue");
            Console.ReadLine();
            NewTest1 t = new NewTest1();
        }
        catch
        {
            Console.WriteLine("Exception thrown");
        }

        Console.WriteLine("Press any key to continue");
        Console.ReadLine();

        System.GC.Collect();

        Console.WriteLine("Press any key to continue");
        Console.ReadLine();           

    }
}

public class NewTest1
{
    public int I { get; set; }
    public NewTest1()
    {
        I = 10;
        throw new ApplicationException("Not Possible");
    }
}

public class NewTest
{
    public int I { get; set; }
    public NewTest(out Object obj)
    {
        obj = this;
        I = 10;
        throw new ApplicationException("Not Possible");
    }
  }
 }

【问题讨论】:

  • GC 真的很喜欢没有被引用的对象。不管它关心什么,它认为这是你能写出的最有效的代码 :) 好吧,不计算它现在还必须收集异常对象。您在这里为一个不存在的问题而烦恼。

标签: c# garbage-collection


【解决方案1】:

其他答案都是正确的;我将向他们添加一个有趣的事实,即 其构造函数抛出的可终结对象仍然是最终确定的。这意味着终结器可以对构造函数未正常完成的对象进行操作。 终结器不得假定对象在终结时就已初始化。这是难以编写正确终结器的众多原因中的又一个。

【讨论】:

  • 是的。我同意你的看法@Eric Lippert。你关于终结器的观点也是我认为的有效观点,但我想我改天再试试。感谢您的专家评论。我应该允许多次投票。
【解决方案2】:

如果您在逻辑上看起来 null 只是您的引用可能具有的值。你的代码等于

NewTest t = null;
t = new NewTest();->  the assignment never occurs because you throw exception

所以这个引用的值为null,垃圾收集器没问题。

【讨论】:

  • 我知道对于变量 t 没有问题,但对象实际上分配了内存,因此内存被指向,因为没有根。
【解决方案3】:

在构造函数中抛出异常对于垃圾收集器来说不是问题,而且绝对不会导致内存泄漏。

虽然从堆中分配的内存永远不会进入您的程序,但它可用于操作符 new 的内部实现,它负责确保新创建的实例符合垃圾回收条件。

【讨论】:

  • 我接受了答案。即使我通过 windbg 获得证据,我也会发布有问题的示例,以便更好地理解问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-29
  • 1970-01-01
  • 2019-08-12
  • 1970-01-01
  • 2014-04-03
  • 2016-08-31
相关资源
最近更新 更多