【问题标题】:Is it safe to hold on to exception objects?持有异常对象是否安全?
【发布时间】:2013-01-23 11:11:25
【问题描述】:

我正在创建一个测试记录器,其中将包含有关引发的任何异常的信息,以便可以使用 GUI 正确显示它们。

使用以下构造是否安全:

public class TestLogEntry {
    public System.Exception Exception { get; private set; }

    public TestLogEntry(/*...,*/ System.Exception exception = null) {
        //...

        Exception = exception;
    }
}

或者以下会更好吗?

public class TestLogEntry {
    public string StackTrace { get; private set; }
    public System.Type ExceptionType { get; private set; }
    public string ExceptionMessage { get; private set; }

    public TestLogEntry(/*...,*/ System.Exception exception = null) {
        //...

        if (exception != null) {
            StackTrace = exception.StackTrace;
            ExceptionType = exception.GetType();
            ExceptionMessage = exception.Message;
        }
    }
}

虽然第一种方法更灵活(因为它可以包含额外的自定义数据),但我担心的是:

  • 长时间持有异常对象。
  • 如果异常对象阻止大对象被垃圾回收,则使用大量内存。
  • 脱离上下文访问时返回错误值的异常。

第一季度。上述担忧是否有效?

第二季度。异常对象通常会引用很多其他数据吗?

【问题讨论】:

  • 通常异常对象不会引用大量数据。在日志记录代码执行期间,您应该可以保留异常对象。

标签: c# .net exception logging


【解决方案1】:

您的担忧是正确的:异常对象可能会保留任意其他对象。这在实践中非常罕见。实际上,我从未见过使用过 Exception.Data 属性。但是我已经看到一个Exception 派生类使用自定义字段持有一些大的东西:WebException 有一个WebResponse 属性!

因此,您会发现,即使是像非托管资源这样昂贵的东西,您也可能会保持活力。

我实际上会复制信息并丢弃Exception。记得同时复制InnerException

另一个问题可能是Exception 是一个可变类型。你可以随时抛出它来改变它的堆栈跟踪。出于这个原因,我想捕获它的状态。

内存使用也很重要。异常有一些可能从未使用过的字段。你可以保存它们。此外,将其字段内联到您的日志消息对象中将消除对象标头和对象引用。小幅收获,但在频繁出现异常的情况下可能值得一试。

【讨论】:

  • 关于 WebResponse,响应流可能不再有效。所以应该考虑到这一点。
  • 这也是捕获内部异常的一个好点。
【解决方案2】:

坚持例外是好的。

一般而言,它们不会保存太多数据(堆栈跟踪、错误消息和相关数据),但这并不多。

并且一个异常实例不会影响其他实例,即使是相同类型的实例。

所以:

长时间持有异常对象。

没问题。

如果异常对象阻止大对象被垃圾回收,则使用大量内存。

只有在向异常添加大量数据时才会出现问题 - 如果不这样做,这不是问题。

脱离上下文访问时返回错误值的异常。

不确定这意味着什么 - 什么上下文?异常就是异常。

【讨论】:

  • > 脱离上下文访问时返回错误值的异常。如果异常封装了某个对象并基于该对象返回值,则该对象的状态在稍后阶段发生更改,从而导致异常信息不正确。
  • @LeaHayes 这是可能的,但我认为这不是最好的做法。
【解决方案3】:

我认为您应该意识到,当您写“延长”或“很多”时,这些是相对而非绝对的术语,因此没有人能够说出这些担忧是否过多。我的 10 核机器上有 2Gb 的 RAM,并且我部署到 Windows 服务器,因此内存影响丝毫不会打扰我。也许您正在使用只有几个字节的备用 RAM 的旧 Windows 手机上运行。谁知道?如果您有疑问,请分析您的内存使用情况,但如果内存是一个问题,我会感到惊讶。

一般来说,对我来说更大的担忧是您可能会倾向于使用异常作为向用户显示状态消息的一种方式,这并不酷。 异常条件例外。您甚至可能无法从它们中有意义地恢复,更不用说照常进行了。如果您想保留异常记录,可以将异常记录到数据库(例如使用 log4net),但我认为您最好记录它们而不是保留它们。

【讨论】:

  • 异常消息和堆栈跟踪与我的目标受众(他们本身就是程序员)相关,但我明白你的建议。
  • 内存方面我担心 .NET 或我们正在使用的库中内置的异常可能会引用内存中可能非常大的对象,从而使它们保持“活动”。
猜你喜欢
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 2016-04-11
  • 2013-08-18
  • 2017-05-01
  • 2011-01-28
  • 2017-02-17
  • 2016-03-04
相关资源
最近更新 更多