Setting Objects to Null/Nothing after use in .NET
Asked Answered
C

16

196

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.

Centurion answered 5/8, 2008 at 20:14 Comment(2)
+1 great question. Does anyone know a circumstance under which the compiler will optimize away the assignment altogether? i.e. has anyone looked at MSIL under different circumstances and noted IL for setting an object to null (or the lack thereof).Magnolia
Here's a Microsoft article with an example that sets a var to null (see end of article): learn.microsoft.com/en-us/training/modules/…Goines
O
78

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:

Overarm answered 5/8, 2008 at 20:56 Comment(9)
The rule about not setting to null isn't "hard and fast"...if the object gets put on the large object heap (size is >85K) it will help the GC if you set the object to null when you are done using it.Stereotomy
I agree to a limited extent, but unless you're starting to experience memory pressure then I see no need to 'prematurely optimise' by setting objects to null after use.Overarm
This whole business of "don't prematurely optimize" sounds more like "Prefer slow and don't worry because CPUs are getting faster and CRUD apps don't need speed anyway." It may just be me though. :)Jhvh
What it really means is "The Garbage Collector is better at managing memory than you are." That might be just me though. :)Velutinous
How about if you disposed the object from a reference in a place different than the original (eg. another form), and later you want to check from the original reference if the object was disposed?Schnorr
@BobbyShaftoe: It's probably as wrong to say "premature optimization is bad, always" as it is to jump to the opposite extreme of "sounds more like 'prefer slow'." No reasonable programmer would say either. It's about nuance and being smart about what your optimizing. I'd personally worry about code clarity and THEN ACTUALLY TEST performance as I've personally seen a lot of people (including myself when I was younger) spend wayyyy too much time making the "perfect" algorithm, only to have it save 0.1ms in 100,000 iterations all while readability was completely shot.Crescantia
OK I get it, setting objects, properties, and variables to null doesn't make GC work any faster and thus remove values from memory, but wouldn't it provide a level of obfuscation that would strip the sensitive data of it's context i.e. is this non-referenced 16 character string on the heap "1234567890123456" a password, a credit card number, telephone number, etc?Upgrowth
@Upgrowth - that's not the GC's job. You the developer are responsible for securing/encrypting what is stored in memory. Also, if your machine is so badly compromised that an attacker can read arbitrary memory locations then it's game over already.Overarm
If you're on windows, plenty of apps can scan your app process space whether it's encrypted or not. Same for both Android/iOS. To rely on the OS to keep your data protected in it's own domain is futile. I do this all the time with my apps to make sure there aren't any obvious patterns. That's why I don't see any issue with nulling out sensitive encrypted data, unless the hacker is taking snapshots every 10 milliseconds it would be rare.Gaylagayle
G
38

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.

Gonnella answered 15/8, 2008 at 14:43 Comment(3)
That's an interesting point. I always thought that objects don't go out of scope until after the method in which they are scoped is complete. Unless of course the object is scoped within a Using block or is explicitly set to Nothing or null.Stamp
The preferred way to ensure that they stay alive is to use GC.KeepAlive(someType); See ericlippert.com/2013/06/10/construction-destructionBloomers
For anyone else who wants an explicit answer, a variable is eligible for garbage collection as soon as it has stopped being used, regardless of whether or not it is still "in scope", so explicitly setting to null is pointless. See this question for more detail: stackoverflow.com/questions/17497923Nonstandard
I
13

No don't null objects. You can check out https://web.archive.org/web/20160325050833/http://codebetter.com/karlseguin/2008/04/28/foundations-of-programming-pt-7-back-to-basics-memory/ for more information, but setting things to null won't do anything, except dirty your code.

Inviting answered 5/8, 2008 at 20:23 Comment(3)
Nice and detail explanation about memory in the shared linkDramamine
Link broken. Without linked content, this answer is rather useles and should be deleted.Hafer
As the link doesn't work, it's high time people must understand that providing just links in an answer is useless. We must always provide a summary of what the link provides, and then provide a link, just to accompany what we have written.Butterbur
T
7

Also:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of
Trader answered 5/8, 2008 at 20:37 Comment(0)
M
7

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).

Maryettamaryjane answered 9/8, 2008 at 11:16 Comment(3)
Well, a disposed object should throw ObjectDisposedException if it has already been disposed. This does, as far as I know, require boilerplate code all over the place, but then again, Disposed is a badly thought-out paradigm anyway.Altheaalthee
Ctrl+F for .Dispose(). If you find it, you aren't using IDisposable correctly. The only use for a disposable object should be in the confines of a using-block. And after the using-block, you don't even have access to myField anymore. And within the using block, setting to null is not required, the using-block will dispose the object for you.Solomon
@nicodemus13: Nope. Calling Dispose multiple times should be allowed. Only in cases where that's impossible (some resource needed for the Dispose operation no longer exists) should the object throw. #8924353Icily
C
7

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.

Confluent answered 9/8, 2008 at 12:13 Comment(2)
I tried using custom local scopes once (mostly being a smarta$$). The company exploded.Solomon
On another note: This is because the c# compiler will find local-scoped variables that implement IDisposable, and will call .Dispose (MOST Of the time) when their scope ends. However... SQL Connections are one big time when .Dispose() is never optimized-in. There are some types that require explicit attention, so I personally always do things explicitly just so I don't get bitten.Solomon
S
6

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
 }
Spurious answered 17/4, 2012 at 8:55 Comment(1)
Best to just track this with a separate flag maybe.Exoskeleton
N
5

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.

Nyx answered 5/8, 2008 at 20:32 Comment(2)
That's true, but it also means you should probably refactor your code. I don't think I've ever needed to declare a variable outside of it's intended scope.Inviting
If "variable" is understood to include object fields, then this answer makes a lot of sense. In the case where "variable" means only "local variable" (of a method), then we're probably talking about niche cases here (e.g. a method that runs for a much-longer-than-usual time span).Harkins
B
3

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().

Balthazar answered 11/4, 2012 at 1:12 Comment(1)
Good example showing how setting to null manually means a more fatal error for the caller which is a good thing.Condescending
P
3

Stephen Cleary explains very well in this post: Should I Set Variables to Null to Assist Garbage Collection?

Says:

The Short Answer, for the Impatient Yes, if the variable is a static field, or if you are writing an enumerable method (using yield return) or an asynchronous method (using async and await). Otherwise, no.

This means that in regular methods (non-enumerable and non-asynchronous), you do not set local variables, method parameters, or instance fields to null.

(Even if you’re implementing IDisposable.Dispose, you still should not set variables to null).

The important thing that we should consider is Static Fields.

Static fields are always root objects, so they are always considered “alive” by the garbage collector. If a static field references an object that is no longer needed, it should be set to null so that the garbage collector will treat it as eligible for collection.

Setting static fields to null is meaningless if the entire process is shutting down. The entire heap is about to be garbage collected at that point, including all the root objects.

Conclusion:

Static fields; that’s about it. Anything else is a waste of time.

Pacifically answered 27/3, 2019 at 0:50 Comment(0)
C
1

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.

Crucifixion answered 5/8, 2008 at 20:46 Comment(0)
S
1

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).

Stereotomy answered 17/8, 2008 at 4:46 Comment(0)
C
0

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...

Centurion answered 10/5, 2016 at 13:7 Comment(0)
E
0

I think setting something back to null is messy. Imagine a scenario where the item being set to now is exposed say via property. Now is somehow some piece of code accidentally uses this property after the item is disposed you will get a null reference exception which requires some investigation to figure out exactly what is going on.

I believe framework disposables will allows throw ObjectDisposedException which is more meaningful. Not setting these back to null would be better then for that reason.

Exoskeleton answered 13/9, 2019 at 9:52 Comment(0)
L
0

From my experience of near real time system design(1 second polling of electricity 100s of meters), we achieved better performance making objects null when it was no more needed. Leaving the work to Garbage Collector(GC) was making it slower as memory was gradually increasing in the RAM memory usage of the process over long period say 2-3 hours of 1 second polling of data. Memory was not showing reducing trend but increasing trend. One we made null many such objects after they were not needed, we say almost stabilization of memory, full stabilization of memory we did not attempt as we had 3rd party library which we did not want to change. For our application with a restart of services in few days of continuous operation, we stabilized balance memory disposal delays. GS process priority is low in Windows OS as I understood, may be experts can correct me on this. I feel less peaking RAM will be needed is we make objects null when it is no more required in high performance applications. The wiki reference has written well on this aspect in disadvantages section & the reference of Apple given therein is also good why making null is advantageous for memory intensive and time critical applications in terms of performance. Wiki mentions at https://en.wikipedia.org/wiki/Garbage_collection_(computer_science), "Disadvantages GC uses computing resources to decide which memory to free. Therefore, the penalty for the convenience of not annotating object lifetime manually in the source code is overhead, which can impair program performance. A peer-reviewed paper from 2005 concluded that GC needs five times the memory to compensate for this overhead and to perform as fast as the same program using idealised explicit memory management. The comparison however is made to a program generated by inserting deallocation calls using an oracle, implemented by collecting traces from programs run under a profiler, and the program is only correct for one particular execution of the program. Interaction with memory hierarchy effects can make this overhead intolerable in circumstances that are hard to predict or to detect in routine testing. The impact on performance was given by Apple as a reason for not adopting garbage collection in iOS, despite it being the most desired feature." The reference of Apple why iOS OS has not given GC is also useful and have still kept GC implementation in backlog of requirement in one of the slides released by Apple in their Developer tools kickoff ppt(slides 61-66) for XCode release March 2011; may be later version can substantiate this fact (refer [9] reference of this Wiki at(use Apple user/password to access the ppt) https://developer.apple.com/devcenter/download.action?path=/wwdc_2011/adc_on_itunes__wwdc11_sessions__pdf/300developer_tools_kickoff.pdf).

Lash answered 18/5, 2023 at 13:20 Comment(0)
T
-2

Some object suppose the .dispose() method which forces the resource to be removed from memory.

Tertian answered 5/8, 2008 at 20:21 Comment(2)
No it doesn't; Dispose() does not collect the object - it is used to perform deterministic clean up, typically releasing unmanaged resources.Greisen
Bearing in mind that the determinism applies only to the managed resources, not the unmanaged ones (i.e. memory)Altheaalthee

© 2022 - 2024 — McMap. All rights reserved.