views:

3696

answers:

11

I have the following code:

MemoryStream foo(){
    MemoryStream ms = new MemoryStream();
    // write stuff to ms
    return ms;
}

void bar(){
    MemoryStream ms2 = foo();
    // do stuff with ms2
    return;
}

Is there any chance that the MemoryStream that I've allocated will somehow fail to be disposed of later?

I've got a peer review insisting that I manually close this, and I can't find the information to tell if he has a valid point or not.

+4  A: 

All streams implement IDisposable. Wrap your Memory stream in a using statement and you'll be fine and dandy. The using block will ensure your stream is closed and disposed no matter what.

wherever you call Foo you can do using(MemoryStream ms = foo()) and i think you should still be ok.

Nick
One problem I've run into with this habit is you must be sure the stream is not being used anywhere else. For instance I created a JpegBitmapDecoder pointed to a MemoryStream and returned Frames[0] (thinking it would copy the data into its own internal store) but found that the bitmap would only show up 20% of the time--turned out it was because I was disposing of the memory stream.
chaiguy
If your memory stream must persist (i.e. a using block doesn't make sense), then you should call Dispose and the immediately set the variable to null. If you dispose it, then it's not meant to be used anymore, so you should also set it to null right away. What chaiguy is describing sounds like a resource management issue, because you shouldn't hand out a reference to something unless the thing you're handing it to takes responsibility for disposing it, and the thing handing out the reference knows it's no longer responsible for doing so.
Triynko
A: 

If an object implements IDisposable, you must call the .Dispose method when you're done.

In some objects, Dispose means the same as Close and vice versa, in that case, either is good.

Now, for your particular question, no, you will not leak memory.

Lasse V. Karlsen
"Must" is a very strong word. Whenever there are rules, it's worth knowing the consequences of breaking them. For MemoryStream, there are very few consequences.
Jon Skeet
+8  A: 

If something is Disposable, you should always Dispose it. You should be using a using statement in your bar() method to make sure ms2 gets Disposed.

It will eventually get cleaned up by the garbage collector, but it is always good practice to Dispose. If you run FxCop on your code, it would flag it as a warning.

Rob Prouse
So even though I could have a "using" block, I still should call .Dispose()?
Saif Khan
The using block calls dispose for you.
Nick
I have to disagree with that advice. Often Dispose is just a no-op and calling it just clutters up your code.
Jonathan Allen
For info, in some trivial tests (for a parallel thread), neither FxCop nor VSTS analysis spotted a trivial missed "using"
Marc Gravell
@Grauenwolf: your assertion breaks encapsulation. As a consumer, you shouldn't care whether it is no-op: if it is IDisposable, it is your job to Dispose() it.
Marc Gravell
A: 

I'm no .net expert, but perhaps the problem here is resources, namely the file handle, and not memory. I guess the garbage collector will eventually free the stream, and close the handle, but I think it would always be best practice to close it explicitly, to make sure you flush out the contents to disk.

Steve
A MemoryStream is all in-memory - there's no file handle here.
Jon Skeet
+4  A: 

Calling .Dispose() (or wrapping with Using) is not required.

The reason you call .Dispose() is to release the resource as soon as possible.

Think in terms of, say, the Stack Overflow server, where we have a limited set of memory and thousands of requests coming in. We don't want to wait around for scheduled garbage collection, we want to release that memory ASAP so it's available for new incoming requests.

Jeff Atwood
Calling Dispose on a MemoryStream isn't going to release any memory though. In fact, you can still get at the data in a MemoryStream after you've called Dispose - try it :)
Jon Skeet
-1 While it's true for a MemoryStream, as general advice this is just plain wrong. Dispose is to release *unmanaged* resources, such as file handles or database connections. Memory does not fall into that category. You almost always should wait around for scheduled garbage collection to free memory.
Joe
What's the upside of adopting one coding style for allocating and disposing `FileStream` objects and a different one for `MemoryStream` objects?
Robert Rossney
A FileStream involves *unmanaged* resources which could actually be immediately freed upon calling Dispose. A MemoryStream, on the other hand, stores a *managed* byte array in its _buffer variable, which is not freed at disposal time. In fact, the _buffer is not even nulled in the MemoryStream's Dispose method, which is a SHAMEFUL BUG IMO because nulling the reference could make the memory eligible for GC right at disposal time. Instead, a lingering (but disposed) MemoryStream reference still holds onto memory. Therefore, once you dispose it, you should also null it if it's still in scope.
Triynko
+2  A: 

You won't leak memory, but your code reviewer is correct to indicate you should close your stream. It's polite to do so.

The only situation in which you might leak memory is when you accidentally leave a reference to the stream and never close it. You still aren't really leaking memory, but you are needlessly extending the amount of time that you claim to be using it.

OwenP
> You still aren't really leaking memory, but you are needlessly extending the amount of time that you claim to be using it.Are you sure? Dispose doesn't release memory and calling it late in the function may actually extend the time it cannot be collected.
Jonathan Allen
Yeah, Jonathan has a point. Placing a call to Dispose late in the function could actually cause the compiler to think you need to access the stream instance (to close it) very late in the function. This could be worse than not calling dispose at all (hence avoiding a late-in-function reference to the stream variable), since a compiler could otherwise calculate an optimal release point (a.k.a. "point of last possible use") earlier in the function.
Triynko
+10  A: 

You won't leak anything - at least in the current implementation.

Calling Dispose won't clean up the memory used by MemoryStream any faster. It will stop your stream from being viable for Read/Write calls after the call, which may or may not be useful to you.

If you're absolutely sure that you never want to move from a MemoryStream to another kind of stream, it's not going to do you any harm to not call Dispose. However, it's generally good practice partly because if you ever do change to use a different Stream, you don't want to get bitten by a hard-to-find bug because you chose the easy way out early on. (On the other hand, there's the YAGNI argument...)

The other reason to do it anyway is that a new implementation may introduce resources which would be freed on Dispose.

Jon Skeet
In this case, the function is returning a MemoryStream because it provides "data that can be interpreted differently depending on calling parameters", so it could have been a byte array, but was easier for other reasons to do as a MemoryStream. So it definitely won't be another Stream class.
Coderer
In that case, I'd still *try* to dispose of it just on general principle - build good habits etc - but I wouldn't worry too much if it became tricky.
Jon Skeet
If one is really worried about freeing resources ASAP, null out the reference immediately after your "using" block, so un-managed resources (if there are any) are cleaned up, and the object becomes eligible for garbage collection. If the method is returning right away, it probably won't make much difference, but if you go on to do other things in the method like request more memory, then it certainly may make a difference.
Triynko
@Triynko Not really true: See: http://stackoverflow.com/questions/574019/calling-null-on-a-class-vs-dispose for details.
George Stocker
@George. Well, if you declare the variable *with* the using statement, then it's both disposed and out of scope by the end of the block, so nulling would be pointless (i.e. if the variable goes out of scope (or is about to, or compiler determines it can't be accessed anymore), then there's no need to null it). HOWEVER, my point was that class instance variables and local variables that become useless as a result of a run-time condition before going out of scope, should be set to null to ensure they can be GC'ed ASAP, especially if you are allocating more memory in the meantime.
Triynko
@triynko Raymond Chen had a blog post about the garbage collector recently; basically the gist is that as soon as the last reference is gone, the variable / class instance can be collected. You can never guarantee when the GC is going to collect it, just that it can actually happen before the scope leaves the current method. See: http://blogs.msdn.com/b/oldnewthing/archive/2010/08/10/10048149.aspx
George Stocker
Yeah, that's what I meant when I said "or compiler determines it can't be accessed anymore". That's the "last possible use" case where a variable may be collectible before it would be out of scope according to the source code. There's an interesting post below that Jonathan Allen wrote that calling Dispose can actually prolong the life of the variable, because the presence of the Dispose call represents a reference to the object. I don't know if the compiler would recognize such a late call to dispose is pointless or if it could determine its ok to order the call sooner.
Triynko
A: 

I would recommend wrapping the MemoryStream in bar() in a using statement mainly for consistency:

  • Right now MemoryStream does not free memory on .Dispose(), but it is possible that at some point in the future it might, or you (or someone else at your company) might replace it with your own custom MemoryStream that does, etc.
  • It helps to establish a pattern in your project to ensure all Streams get disposed -- the line is more firmly drawn by saying "all Streams must be disposed" instead of "some Streams must be disposed, but certain ones don't have to"...
  • If you ever change the code to allow for returning other types of Streams, you'll need to change it to dispose anyway.

Another thing I usually do in cases like foo() when creating and returning an IDisposable is to ensure that any failure between constructing the object and the return is caught by an exception, disposes the object, and rethrows the exception:

MemoryStream x = new MemoryStream();
try
{
    // ... other code goes here ...
    return x;
}
catch
{
    // "other code" failed, dispose the stream before throwing out the Exception
    x.Dispose();
    throw;
}
Chris R. Donnelly
A: 

Disposal of unmanaged resources is non-deterministic in garbage collected languages. Even if you call Dispose explicitly, you have absolutely no control over when the backing memory is actually freed. Dispose is implicitly called when an object goes out of scope, whether it be by exiting a using statement, or popping up the callstack from a subordinate method. This all being said, sometimes the object may actually be a wrapper for a managed resource (e.g. file). This is why it's good practice to explicitly close in finally statements or to use the using statement. Cheers

Not exactly true.Dispose is called when exiting a using statement.Dispose is not called when an object just goes out of scope.
Alexander Abramov
+1  A: 

This is already answered, but I'll just add that the good old-fashioned principle of information hiding means you may at some future point want to refactor:

MemoryStream foo()
{    
    MemoryStream ms = new MemoryStream();    
    // write stuff to ms    
    return ms;
}

to:

Stream foo()
{    
   ...
}

This emphasizes that callers should not care what kind of Stream is being returned, and makes it possible to change the internal implementation (e.g. when mocking for unit testing).

You then will need be in trouble if you haven't used Dispose in your bar implementation:

void bar()
{    
    using (Stream s = foo())
    {
        // do stuff with s
        return;
    }
}
Joe
A: 

Yes there's a leak, depending on how you define LEAK and how much LATER you mean...

If by leak you mean "the memory remains allocated, unavailable for use, even though you're done using it" and by later you mean anytime after calling dispose, then then yes there may be a leak, although its not permanent (i.e. for the life of your applications runtime).

To free the managed memory used by the MemoryStream, you need to unreference it, by nullifying your reference to it, so it becomes eligible for garbage collection right away. If you fail to do this, then you create a temporary leak from the time you're done using it, until your reference goes out of scope, because in the meantime the memory will not be available for allocation.

The benefit of the using statement (over simply calling dispose) is that you can DECLARE your reference in the using statement. When the using statement finishes, not only is dispose called, but your reference goes out of scope, effectively nullifying the reference and making your object eligible for garbage collection immediately without requiring you to remember to write the "reference=null" code.

While failing to unreference something right away is not a classical "permanent" memory leak, it definitely has the same effect. For example, if you keep your reference to the MemoryStream (even after calling dispose), and a little further down in your method you try to allocate more memory... the memory in use by your still-referenced memory stream will not be available to you until you nullify the reference or it goes out of scope, even though you called dispose and are done using it.

Triynko
I love this response. Sometimes people forget the dual duty of using: eager resource reclamation *and* eager dereferencing.
Kit
Indeed, although I heard that unlike Java, the C# compiler detects "last possible use", so if the variable is destined to go out of scope after its last reference, it may become eligible for garbage collection right after its last possible use... before it actually goes out of scope. See http://stackoverflow.com/questions/680550/explicit-nulling
Triynko