使用try / finally是一个很好的内存管理实践吗?

时间:2016-12-21 08:11:44

标签: c# garbage-collection try-finally

我的一位大四学生告诉我使用try/ finally块来清除初始化对象数据的所有方法。 例如:

var serviceProxy = new NotificationServiceProxy();
try
{
     return serviceProxy.GetNotifications(userID, request.Filters, request.FilterProperty, usertypeid);
}
finally
{
     serviceProxy = null;
}

这是一个好习惯吗?如果我使用try/ catch用于我的所有方法来清除初始化的对象数据。

7 个答案:

答案 0 :(得分:3)

不在C#中,请改用using

using(var serviceProxy = new NotificationServiceProxy()){
    serviceProxy.GetNotifications(userID, request.Filters, request.FilterProperty, usertypeid);
    // Do stuff with the service proxy
}

// serviceProxy has now been cleaned up

这是确保清除IDisposable变量的模式。

对于不是一次性的实例,不需要 - 只需让它们超出范围并将其留给GC。

如果NotificationServiceProxy使用了大量资源,并且您需要确保它已正确完成,那么请将其设置为一次性并始终将其包装在using或另一个同时实现{{1}的类中}。如果没有,那么这种IDisposable模式就是浪费时间。

答案 1 :(得分:3)

不,是一种好习惯。

  • 您正在手动工作,编译器/垃圾收集器将为您完成。这是您花费的不必要的时间和以后需要删除或维护的不必要的代码混乱。

  • 您完全错过了.Dispose()服务参考。虽然可以在finally块中完成,但using块完全存在于此目的。

答案 2 :(得分:1)

您不需要清除本地变量。在退出方法之前,无论如何都将还原堆栈(这将释放变量使用的堆栈上的空间)并将局部变量设置为null将不会释放堆上的空间(垃圾收集器)会这样做)。如果需要进行一些清理,请使用try finally,例如对象处理或关闭文件。

答案 3 :(得分:0)

这是一个好的做法,它取决于场景。捕获异常通常很好,这样您就可以优雅地处理意外情况。如果你的程序已经开发了一些其他方法来处理异常情况,那么Try / Finally块就足够了,因为Catch块会有一些性能损失。

请查看MSDN上的Consideration When Using Try Catch文章。

答案 4 :(得分:0)

首先,您无需清除局部变量(垃圾收集器会为您执行此操作),但是,它是安全的:

 Object o = new Object(); 
 ...
 o = null; // safe, but not required

您需要做的是清除非托管资源;典型的方法是实现IDisposable接口并将相应的实例包装到using

 // Providing that serviceProxy implements IDisposable
 using (var serviceProxy = new NotificationServiceProxy()) {
   return serviceProxy.GetNotifications(
     userID, 
     request.Filters, 
     request.FilterProperty, 
     usertypeid);
 } // <- here .Net will call serviceProxy.Dispose() and free the resources allocated

有时你必须恢复初始状态try..finally的设计就是这样:

  Cursor savedCursor = Cursor.Current;

  try {
    Cursor.Current = Cursors.WaitCursor;
    ... 
  }
  finally {
    // Rain (exception thrown) or shine (no exception), please, restore my cursor
    Cursor.Current = savedCursor;
  }

在您的特定情况下,我看不到任何要恢复的状态,这就是为什么try..finally不是应该使用的模式的原因。但是,serviceProxy很可能会分配一些非托管资源(例如,TCP / IP端口,连接或类似),因此您似乎应该为{{1}实现IDisposable class(如果它还没有实现)并将实例包装到NotificationServiceProxy

答案 5 :(得分:0)

当你需要像处理IDisposable对象那样 HAS 时,这是有道理的,无论你的操作是失败还是成功。

try
{
    myDisposable.Do();
}
finally
{
    myDisposable.Dispose(); 
}

你有一个内置的机制,它正是这样做的:使用

using(IDisposable myDisposable = new Something())
{
    myDisposable.Do();
}

现在必须做好准备:

这取决于您的错误处理策略和清理需求:

  • 如果我有一些 HAS 要做的事情,无论操作成功还是失败,我都会尝试一下try块。

  • 如果我的东西只需要错误处理而且没有清理我会把try catch放在没有finally块的情况下

  • 如果我必须进行某种错误处理,我也会在那里放置一个catch块

  • 如果我不想在日志中进行一些错误处理,然后让异常从该堆栈传播,我也会抛出异常。

或上述条件的任何排列..

例如:

 try
 {
     myDisposable.Do();
 }
 catch(Exception e)
 {
     Log("Error at something something",e); 
     throw e;
 }
 finally
 {
     myDisposable.Dispose(); 
 }

我一个人最后不要尝试捕获每个地方,我希望我的代码中包含它们的地方突出显示这些是因某些已知原因而出错的操作。

我欢迎新的例外情况,我还没有意识到并相应地处理它们。

答案 6 :(得分:-7)

是的,如果您需要处理变量。