可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Should you set all the objects to null
(Nothing
in VB.NET) once you have finished with them?
I understand that in .NET it is essential to dispose of any instances of objects that implement the IDisposable
interface to release some resources although the object can still be something after it is disposed (hence the isDisposed
property in forms), so I assume it can still reside in memory or at least in part?
I also know that when an object goes out of scope it is then marked for collection ready for the next pass of the garbage collector (although this may take time).
So with this in mind will setting it to null
speed up the system releasing the memory as it does not have to work out that it is no longer in scope and are they any bad side effects?
MSDN articles never do this in examples and currently I do this as I cannot
see the harm. However I have come across a mixture of opinions so any comments are useful.
回答1:
Karl is absolutely correct, there is no need to set objects to null after use. If an object implements IDisposable
, just make sure you call IDisposable.Dispose()
when you\'re done with that object (wrapped in a try
..finally
, or, a using()
block). But even if you don\'t remember to call Dispose()
, the finaliser method on the object should be calling Dispose()
for you.
I thought this was a good treatment:
Digging into IDisposable
and this
Understanding IDisposable
There isn\'t any point in trying to second guess the GC and its management strategies because it\'s self tuning and opaque. There was a good discussion about the inner workings with Jeffrey Richter on Dot Net Rocks here: Jeffrey Richter on the Windows Memory Model and
Richters book CLR via C# chapter 20 has a great treatment:
回答2:
Another reason to avoid setting objects to null when you are done with them is that it can actually keep them alive for longer.
e.g.
void foo()
{
var someType = new SomeType();
someType.DoSomething();
// someType is now eligible for garbage collection
// ... rest of method not using \'someType\' ...
}
will allow the object referred by someType to be GC\'d after the call to \"DoSomething\" but
void foo()
{
var someType = new SomeType();
someType.DoSomething();
// someType is NOT eligible for garbage collection yet
// because that variable is used at the end of the method
// ... rest of method not using \'someType\' ...
someType = null;
}
may sometimes keep the object alive until the end of the method. The JIT will usually optimized away the assignment to null, so both bits of code end up being the same.
回答3:
No don\'t null objects. You can check out http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx for more information, but setting things to null won\'t do anything, except dirty your code.
回答4:
Also:
using(SomeObject object = new SomeObject())
{
// do stuff with the object
}
// the object will be disposed of
回答5:
In general, there\'s no need to null objects after use, but in some cases I find it\'s a good practice.
If an object implements IDisposable and is stored in a field, I think it\'s good to null it, just to avoid using the disposed object. The bugs of the following sort can be painful:
this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();
It\'s good to null the field after disposing it, and get a NullPtrEx right at the line where the field is used again. Otherwise, you might run into some cryptic bug down the line (depending on exactly what DoSomething does).
回答6:
Chances are that your code is not structured tightly enough if you feel the need to null
variables.
There are a number of ways to limit the scope of a variable:
As mentioned by Steve Tranby
using(SomeObject object = new SomeObject())
{
// do stuff with the object
}
// the object will be disposed of
Similarly, you can simply use curly brackets:
{
// Declare the variable and use it
SomeObject object = new SomeObject()
}
// The variable is no longer available
I find that using curly brackets without any \"heading\" to really clean out the code and help make it more understandable.
回答7:
The only time you should set a variable to null is when the variable does not go out of scope and you no longer need the data associated with it. Otherwise there is no need.
回答8:
In general no need to set to null. But suppose you have a Reset functionality in your class.
Then you might do, because you do not want to call dispose twice, since some of the Dispose may not be implemented correctly and throw System.ObjectDisposed exception.
private void Reset()
{
if(_dataset != null)
{
_dataset.Dispose();
_dataset = null;
}
//..More such member variables like oracle connection etc. _oraConnection
}
回答9:
this kind of \"there is no need to set objects to null after use\" is not entirely accurate. There are times you need to NULL the variable after disposing it.
Yes, you should ALWAYS call .Dispose()
or .Close()
on anything that has it when you are done. Be it file handles, database connections or disposable objects.
Separate from that is the very practical pattern of LazyLoad.
Say I have and instantiated ObjA
of class A
. Class A
has a public property called PropB
of class B
.
Internally, PropB
uses the private variable of _B
and defaults to null. When PropB.Get()
is used, it checks to see if _PropB
is null and if it is, opens the resources needed to instantiate a B
into _PropB
. It then returns _PropB
.
To my experience, this is a really useful trick.
Where the need to null comes in is if you reset or change A in some way that the contents of _PropB
were the child of the previous values of A
, you will need to Dispose AND null out _PropB
so LazyLoad can reset to fetch the right value IF the code requires it.
If you only do _PropB.Dispose()
and shortly after expect the null check for LazyLoad to succeed, it won\'t be null, and you\'ll be looking at stale data. In effect, you must null it after Dispose()
just to be sure.
I sure wish it were otherwise, but I\'ve got code right now exhibiting this behavior after a Dispose()
on a _PropB
and outside of the calling function that did the Dispose (and thus almost out of scope), the private prop still isn\'t null, and the stale data is still there.
Eventually, the disposed property will null out, but that\'s been non-deterministic from my perspective.
The core reason, as dbkk alludes is that the parent container (ObjA
with PropB
) is keeping the instance of _PropB
in scope, despite the Dispose()
.
回答10:
There are some cases where it makes sense to null references. For instance, when you\'re writing a collection--like a priority queue--and by your contract, you shouldn\'t be keeping those objects alive for the client after the client has removed them from the queue.
But this sort of thing only matters in long lived collections. If the queue\'s not going to survive the end of the function it was created in, then it matters a whole lot less.
On a whole, you really shouldn\'t bother. Let the compiler and GC do their jobs so you can do yours.
回答11:
Take a look at this article as well: http://www.codeproject.com/KB/cs/idisposable.aspx
For the most part, setting an object to null has no effect. The only time you should be sure to do so is if you are working with a \"large object\", which is one larger than 84K in size (such as bitmaps).
回答12:
I believe by design of the GC implementors, you can\'t speed up GC with nullification. I\'m sure they\'d prefer you not worry yourself with how/when GC runs -- treat it like this ubiquitous Being protecting and watching over and out for you...(bows head down, raises fist to the sky)...
Personally, I often explicitly set variables to null when I\'m done with them as a form of self documentation. I don\'t declare, use, then set to null later -- I null immediately after they\'re no longer needed. I\'m saying, explicitly, \"I\'m officially done with you...be gone...\"
Is nullifying necessary in a GC\'d language? No. Is it helpful for the GC? Maybe yes, maybe no, don\'t know for certain, by design I really can\'t control it, and regardless of today\'s answer with this version or that, future GC implementations could change the answer beyond my control. Plus if/when nulling is optimized out it\'s little more than a fancy comment if you will.
I figure if it makes my intent clearer to the next poor fool who follows in my footsteps, and if it \"might\" potentially help GC sometimes, then it\'s worth it to me. Mostly it makes me feel tidy and clear, and Mongo likes to feel tidy and clear. :)
I look at it like this: Programming languages exist to let people give other people an idea of intent and a compiler a job request of what to do -- the compiler converts that request into a different language (sometimes several) for a CPU -- the CPU(s) could give a hoot what language you used, your tab settings, comments, stylistic emphases, variable names, etc. -- a CPU\'s all about the bit stream that tells it what registers and opcodes and memory locations to twiddle. Many things written in code don\'t convert into what\'s consumed by the CPU in the sequence we specified. Our C, C++, C#, Lisp, Babel, assembler or whatever is theory rather than reality, written as a statement of work. What you see is not what you get, yes, even in assembler language.
I do understand the mindset of \"unnecessary things\" (like blank lines) \"are nothing but noise and clutter up code.\" That was me earlier in my career; I totally get that. At this juncture I lean toward that which makes code clearer. It\'s not like I\'m adding even 50 lines of \"noise\" to my programs -- it\'s a few lines here or there.
There are exceptions to any rule. In scenarios with volatile memory, static memory, race conditions, singletons, usage of \"stale\" data and all that kind of rot, that\'s different: you NEED to manage your own memory, locking and nullifying as apropos because the memory is not part of the GC\'d Universe -- hopefully everyone understands that. The rest of the time with GC\'d languages it\'s a matter of style rather than necessity or a guaranteed performance boost.
At the end of the day make sure you understand what is eligible for GC and what\'s not; lock, dispose, and nullify appropriately; wax on, wax off; breathe in, breathe out; and for everything else I say: If it feels good, do it. Your mileage may vary...as it should...
回答13:
Some object suppose the .dispose()
method which forces the resource to be removed from memory.