你需要处理对象并将它们设置为null吗?

本文翻译自:Do you need to dispose of objects and set them to null?

您是否需要处理对象并将它们设置为null,或者当垃圾收集器超出范围时它们是否会将它们清理干净?


#1楼

参考:https://stackoom.com/question/chpz/你需要处理对象并将它们设置为null吗


#2楼

If they implement the IDisposable interface then you should dispose them. 如果他们实现IDisposable接口,那么你应该处理它们。 The garbage collector will take care of the rest. 垃圾收集器将处理其余的事情。

EDIT: best is to use the using command when working with disposable items: 编辑:最好是在处理一次性物品时使用using命令:

using(var con = new SqlConnection("..")){ ...

#3楼

You never need to set objects to null in C#. 您永远不需要在C#中将对象设置为null。 The compiler and runtime will take care of figuring out when they are no longer in scope. 编译器和运行时将负责确定它们何时不在范围内。

Yes, you should dispose of objects that implement IDisposable. 是的,您应该处理实现IDisposable的对象。


#4楼

If the object implements IDisposable , then yes, you should dispose it. 如果对象实现了IDisposable ,那么是的,你应该处理它。 The object could be hanging on to native resources (file handles, OS objects) that might not be freed immediately otherwise. 该对象可能会挂起到本机资源(文件句柄,OS对象),否则可能无法立即释放。 This can lead to resource starvation, file-locking issues, and other subtle bugs that could otherwise be avoided. 这可能导致资源匮乏,文件锁定问题以及其他可能无法避免的细微错误。

See also Implementing a Dispose Method on MSDN. 另请参阅在MSDN上实现Dispose方法


#5楼

Objects will be cleaned up when they are no longer being used and when the garbage collector sees fit. 当物体不再被使用以及垃圾收集器看起来合适时,物体将被清理干净。 Sometimes, you may need to set an object to null in order to make it go out of scope (such as a static field whose value you no longer need), but overall there is usually no need to set to null . 有时,您可能需要将对象设置为null以使其超出范围(例如,您不再需要其值的静态字段),但总体上通常不需要设置为null

Regarding disposing objects, I agree with @Andre. 关于处理对象,我同意@Andre。 If the object is IDisposable it is a good idea to dispose it when you no longer need it, especially if the object uses unmanaged resources. 如果对象是IDisposable最好在不再需要它时将其处理掉 ,特别是如果对象使用非托管资源。 Not disposing unmanaged resources will lead to memory leaks . 不处理非托管资源会导致内存泄漏

You can use the using statement to automatically dispose an object once your program leaves the scope of the using statement. 一旦程序离开using语句的范围,就可以使用using语句自动释放对象。

using (MyIDisposableObject obj = new MyIDisposableObject())
{
    // use the object here
} // the object is disposed here

Which is functionally equivalent to: 这在功能上等同于:

MyIDisposableObject obj;
try
{
    obj = new MyIDisposableObject();
}
finally
{
    if (obj != null)
    {
        ((IDisposable)obj).Dispose();
    }
}

#6楼

Objects never go out of scope in C# as they do in C++. 对象永远不会像在C ++中那样超出C#的范围。 They are dealt with by the Garbage Collector automatically when they are not used anymore. 它们在不再使用时由垃圾收集器自动处理。 This is a more complicated approach than C++ where the scope of a variable is entirely deterministic. 这是一种比C ++更复杂的方法,其中变量的范围完全是确定性的。 CLR garbage collector actively goes through all objects that have been created and works out if they are being used. CLR垃圾收集器主动遍历已创建的所有对象,如果正在使用它们,则会计算出来。

An object can go "out of scope" in one function but if its value is returned, then GC would look at whether or not the calling function holds onto the return value. 对象可以在一个函数中“超出范围”,但如果返回其值,则GC将查看调用函数是否保留在返回值上。

Setting object references to null is unnecessary as garbage collection works by working out which objects are being referenced by other objects. 将对象引用设置为null是不必要的,因为垃圾收集通过计算其他对象正在引用哪些对象来工作。

In practice, you don't have to worry about destruction, it just works and it's great :) 在实践中,你不必担心破坏,它只是工作,它是伟大的:)

Dispose must be called on all objects that implement IDisposable when you are finished working with them. 必须在完成使用IDisposable所有对象上调用Dispose Normally you would use a using block with those objects like so: 通常你会使用带有这些对象的using块,如下所示:

using (var ms = new MemoryStream()) {
  //...
}

EDIT On variable scope. 编辑可变范围。 Craig has asked whether the variable scope has any effect on the object lifetime. Craig已经询问变量范围是否对对象生命周期有任何影响。 To properly explain that aspect of CLR, I'll need to explain a few concepts from C++ and C#. 为了正确解释CLR的这个方面,我需要从C ++和C#中解释一些概念。

Actual variable scope 实际变量范围

In both languages the variable can only be used in the same scope as it was defined - class, function or a statement block enclosed by braces. 在这两种语言中,变量只能在与定义相同的范围内使用 - 类,函数或括号括起来的语句块。 The subtle difference, however, is that in C#, variables cannot be redefined in a nested block. 然而,细微差别在于,在C#中,无法在嵌套块中重新定义变量。

In C++, this is perfectly legal: 在C ++中,这是完全合法的:

int iVal = 8;
//iVal == 8
if (iVal == 8){
    int iVal = 5;
    //iVal == 5
}
//iVal == 8

In C#, however you get aa compiler error: 但是在C#中,您会遇到编译器错误:

int iVal = 8;
if(iVal == 8) {
    int iVal = 5; //error CS0136: A local variable named 'iVal' cannot be declared in this scope because it would give a different meaning to 'iVal', which is already used in a 'parent or current' scope to denote something else
}

This makes sense if you look at generated MSIL - all the variables used by the function are defined at the start of the function. 如果查看生成的MSIL,这是有意义的 - 函数使用的所有变量都是在函数的开头定义的。 Take a look at this function: 看看这个功能:

public static void Scope() {
    int iVal = 8;
    if(iVal == 8) {
        int iVal2 = 5;
    }
}

Below is the generated IL. 以下是生成的IL。 Note that iVal2, which is defined inside the if block is actually defined at function level. 请注意,在if块中定义的iVal2实际上是在功能级别定义的。 Effectively this means that C# only has class and function level scope as far as variable lifetime is concerned. 实际上,这意味着就可变生命周期而言,C#仅具有类和功能级别范围。

.method public hidebysig static void  Scope() cil managed
{
  // Code size       19 (0x13)
  .maxstack  2
  .locals init ([0] int32 iVal,
           [1] int32 iVal2,
           [2] bool CS$4$0000)

//Function IL - omitted
} // end of method Test2::Scope

C++ scope and object lifetime C ++范围和对象生存期

Whenever a C++ variable, allocated on the stack, goes out of scope it gets destructed. 每当在堆栈上分配的C ++变量超出范围时,它就会被破坏。 Remember that in C++ you can create objects on the stack or on the heap. 请记住,在C ++中,您可以在堆栈或堆上创建对象。 When you create them on the stack, once execution leaves the scope, they get popped off the stack and gets destroyed. 当您在堆栈上创建它们时,一旦执行离开作用域,它们就会从堆栈中弹出并被销毁。

if (true) {
  MyClass stackObj; //created on the stack
  MyClass heapObj = new MyClass(); //created on the heap
  obj.doSomething();
} //<-- stackObj is destroyed
//heapObj still lives

When C++ objects are created on the heap, they must be explicitly destroyed, otherwise it is a memory leak. 在堆上创建C ++对象时,必须显式销毁它们,否则会导致内存泄漏。 No such problem with stack variables though. 虽然堆栈变量没有这样的问题。

C# Object Lifetime C#对象生命周期

In CLR, objects (ie reference types) are always created on the managed heap. 在CLR中, 始终在托管堆上创建对象(即引用类型)。 This is further reinforced by object creation syntax. 对象创建语法进一步强化了这一点。 Consider this code snippet. 请考虑此代码段。

MyClass stackObj;

In C++ this would create an instance on MyClass on the stack and call its default constructor. 在C ++中,这将在堆栈上的MyClass上创建一个实例并调用其默认构造函数。 In C# it would create a reference to class MyClass that doesn't point to anything. 在C#中,它将创建一个对MyClass类的引用,它不指向任何东西。 The only way to create an instance of a class is by using new operator: 创建类实例的唯一方法是使用new运算符:

MyClass stackObj = new MyClass();

In a way, C# objects are a lot like objects that are created using new syntax in C++ - they are created on the heap but unlike C++ objects, they are managed by the runtime, so you don't have to worry about destructing them. 在某种程度上,C#对象很像在C ++中使用new语法创建的对象 - 它们是在堆上创建的,但与C ++对象不同,它们由运行时管理,因此您不必担心破坏它们。

Since the objects are always on the heap the fact that object references (ie pointers) go out of scope becomes moot. 由于对象总是在堆上,因此对象引用(即指针)超出范围的事实变得没有实际意义。 There are more factors involved in determining if an object is to be collected than simply presence of references to the object. 确定是否要收集对象涉及的因素多于简单地存在对象的引用。

C# Object references C#对象引用

Jon Skeet compared object references in Java to pieces of string that are attached to the balloon, which is the object. Jon Skeet 将Java中的对象引用与附加到气球(即对象)的字符串进行了比较。 Same analogy applies to C# object references. 相同的类比适用于C#对象引用。 They simply point to a location of the heap that contains the object. 它们只是指向包含该对象的堆的位置。 Thus, setting it to null has no immediate effect on the object lifetime, the balloon continues to exist, until the GC "pops" it. 因此,将其设置为null对对象生命周期没有立即影响,气球继续存在,直到GC“弹出”它。

Continuing down the balloon analogy, it would seem logical that once the balloon has no strings attached to it, it can be destroyed. 继续按照气球的比喻,似乎合乎逻辑的是,一旦气球没有任何附加条件,它就会被摧毁。 In fact this is exactly how reference counted objects work in non-managed languages. 实际上,这正是引用计数对象在非托管语言中的工作方式。 Except this approach doesn't work for circular references very well. 除非这种方法不适用于循环引用。 Imagine two balloons that are attached together by a string but neither balloon has a string to anything else. 想象一下两个气球通过一个字符串连接在一起,但气球都没有任何其他字符串。 Under simple ref counting rules, they both continue to exist, even though the whole balloon group is "orphaned". 在简单的引用计数规则下,它们都会继续存在,即使整个气球组是“孤立的”。

.NET objects are a lot like helium balloons under a roof. .NET对象很像屋顶下的氦气球。 When the roof opens (GC runs) - the unused balloons float away, even though there might be groups of balloons that are tethered together. 当屋顶打开(GC运行)时 - 未使用的气球会漂浮,即使可能有一组气球系在一起。

.NET GC uses a combination of generational GC and mark and sweep. .NET GC使用世代GC和标记和扫描的组合。 Generational approach involves the runtime favouring to inspect objects that have been allocated most recently, as they are more likely to be unused and mark and sweep involves runtime going through the whole object graph and working out if there are object groups that are unused. 分代方法涉及运行时有利于检查最近分配的对象,因为它们更可能未被使用,并且标记和扫描涉及运行时通过整个对象图并且如果存在未使用的对象组则进行计算。 This adequately deals with circular dependency problem. 这充分解决了循环依赖问题。

Also, .NET GC runs on another thread(so called finalizer thread) as it has quite a bit to do and doing that on the main thread would interrupt your program. 此外,.NET GC在另一个线程(所谓的终结器线程)上运行,因为它有很多工作要做,在主线程上这样做会中断你的程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值