Dispose and memorystream - c#

I have the following code that gets called 4 times a second and updates the background of a grid. When i don't dispose of of the memory stream, the memory output usage slowly grows and falls. MemoryStream has a Dispose function, But if I call it even after i dispose the Source Bitmap, the background is just white.
Do i need to dispose the stream? And if I do, what am I doing wrong?
private void Viewer_OnUpdate(object self, Bitmap sourceBitmap, Int32Rect cropArea)
{
if (sourceBitmap == null)
{
return;
}
this.Dispatcher.BeginInvoke(DispatcherPriority.Render,
new Action(
() =>
{
MemoryStream stream = new MemoryStream();
sourceBitmap.Save(stream, ImageFormat.Bmp);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
stream.Seek(0, SeekOrigin.Begin);
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
this.GridContainer.Background =
new ImageBrush(new CroppedBitmap(bitmapImage,cropArea));
sourceBitmap.Dispose();
}));
}
Note: i'm dispatching because the calling event is always from a Non-UI thread

From MSDN documentation for BitmapImage (emphasis is mine):
Set the CacheOption property to BitmapCacheOption.OnLoad if you wish
to close the stream after the BitmapImage is created. The default
OnDemand cache option retains access to the stream until the bitmap is
needed, and cleanup is handled by the garbage collector.

First, you discovered that if you dispose the memory stream, the bitmap is affected, which means your ImageBrush seems white. So - don't dispose the memory stream.
Second, and more importantly, the memory consumption pattern you're seeing - more and more memory, then a sudden fall - is normal. That's what happens when the garbage collector runs at its own discretion. It's not a problem at all.
So don't dispose of the memory stream, let the garbage collector do its job, and don't worry about it.

Look, maybe this answer will help you.
MemoryStream in Using Statement - Do I need to call close()
If you put your MemoryStream in a using statement, you will not need to Dispose, because it will do it automatically ;)
I hope this helps

Related

PngBitmapEncoder failling

I'm loading bitmaps on one thread, and then later saving them to disk on another thread.
Loading on Thread A :
BitmapSource bitmapSource = null;
using (var stream = File.OpenRead(path))
{
bitmapSource = BitmapDecoder
.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad).Frames[0];
bitmapSource.Freeze();
}
// only available to Thread B at this point (i.e after loading is complete).
Saving on Thread B :
System.Diagnostics.Debug.Assert(bitmapSource.IsFrozen);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource)); <-- Exception here
...
99% of the time, this works fine. But every once in a while, I'll get an exception at the 'BitmapFrame.Create(bitmapSource)' point, with the following call stack :
at System.Windows.Threading.Dispatcher.VerifyAccess()
at System.Windows.Media.Imaging.BitmapDecoder.get_IsDownloading()
at System.Windows.Media.Imaging.BitmapFrameDecode.get_InternalMetadata()
at System.Windows.Media.Imaging.BitmapFrame.Create(BitmapSource source)
The calling thread cannot access this object because a different thread owns it.
I'm really not sure what is going on. From my understanding, as long as you freeze the bitmapsource, you can access it from another thread? I also have a debug assert to check it is frozen, which never gets triggered. And if I check all the properties of the bitmapsource object in the debugger, I see the following :
All properties are accessable apart from the IsDownloading one. I'm not doing any downloading. I'm loading the bitmap from disk, and it's not available to the second thread until its completed loading? so it's a bit of a mystery, at least to me.
I came across this :
WPF BitmapFrame and multiple threads
The solution appears to be to wrap the bitmap in a CachedBitmap
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(new CachedBitmap(x, BitmapCreateOptions.None, BitmapCacheOption.OnLoad)));
Ideally, you could use CheckAccess() to determine it this extra step is necessary rather than always doing it, but CheckAccess() always returns true for some reason.

Memory not getting released in WPF Image

I am loading and unloading images in Canvas. I used the below code to load the Image.
Before loading my Image the memory consumption is 14.8MB.
Canvas c = new Canvas();
Image im = new Image();
ImageSource src = new BitmapImage(new Uri(#"E:Capture.png"));
im.Source = src;
im.Height = 800;
im.Width = 800;
c.Children.Add(im);
homegrid.Children.Add(c); //homegrid is my grid's name
The Image displayed correctly and the memory consumption now is 20.8MB. Then I unloaded the Image by the below code:
foreach (UIElement element in homegrid.Children)
{
if (element is Canvas)
{
Canvas page = element as Canvas;
if (page.Children.Count > 0)
{
for (int i = page.Children.Count - 1; i >= 0; i--)
{
if (page.Children[i] is Image)
(page.Children[i] as Image).Source = null;
page.Children.RemoveAt(i);
}
}
page.Children.Clear();
page = null;
}
}
homegrid.Children.RemoveAt(2);
InvalidateVisual();
The Image gets removed after this, but the memory is still 20.8 MB.
Can anyone help me out this?
First of all you should test by explicitly invoking GC.Collect() to collect memory and see that memory releases or not because GC collection is indeterministic. You can't be sure that after your method execution GC runs and reclaim the memory.
So , at end put this code to explicitly force GC to run to check if actually memory is released or not:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
However, there is some known memory leak issues in BitmapImage creation which you can refer here, here and here.
Actually under the covers WPF keeps a strong reference between the static BitmapImage and the Image and hook some events on Bitmap image. So, you should freeze the bitmapImage before assigning to image. WPF doesn't hook events on freezed bitmapImage. Also set CacheOption to avoid any caching memory leak of bitmapImage.
Image im = new Image();
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri(#"E:Capture.png");
bi.EndInit();
bi.Freeze();
ImageSource src = bi;
im.Source = src;
im.Height = 800;
im.Width = 800;
In .Net there is something called the garbage collector (GC) that is in charge of managing the memory you're using.
When you create an instance of an object, it requires some more memory.
When you remove your ImageSource from the Children collection, you don't actually free any memory, you just say "I don't want to use this instance anymore".
At this point the GC will help you. It'll automatically detect instances that are not used anymore, and will free the associated memory for you.
Do note it's an automatic process and you shouldn't (and you don't want to) take care of the memory management.
You can call GC.Collect(); to force the garbage collector to do its job right now, you'll see the memory will be released. NOTE: GC.Collect(); should be used in debug to detect memory leaks, but 99% of times you shouldn't call it explicitly in production code. GC.Collect(); is an operation that can use a lot of CPU time.

"using" statment inside method can cause troubles of data corruption or Access violation?

I have a task, that set data into a FIFO, then another thread read this data inside the FIFO one by one and send it via network later. The data converted to byte array when call FIFO.Add, as following:
public byte[] ByteArraySerialize()
{
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(m))
{
writer.Write((int)this.Opcode);
writer.Write(this.Data);
}
return m.ToArray();
}
}
My question: Is it possible that the data will be corrupted or disposed before the sender thread reads it from FIFO? My question is to understand using inside method:
Is this the way of using the using inside a method may cause GC to remove the MemoryStream, before the thread reads the data lets say after few second or minutes after this data entered the FIFO?
There are multiple ways to read this question but let's start with the obvious way, the way it was written:
Is this way of using the "using" inside a method may cause GC to remove the Memory Stream, before the thread read the data lets say after few second or minutest after this data enter the FIFO?
No. This will not be a problem. If you are able to read the data as part of the call to .ToArray(), then you already have a copy of the data. If GC later on collects the stream, the array will live on. To be clear, in relation to GC, if you can read a good copy of the internals of the stream at the point where you call .ToArray(), then that array will be OK afterwards. As per the documentation, you're getting a copy of the internal data, not a reference to it, and even so, if you have a reference to some internal data structure, GC will not be able to collect it.
However, another interpretation could be this: Is there something wrong with this code?
And well, yes, and no.
The current implementation of BinaryWriter will dispose of the underlying stream when the writer instance is disposed of. This means that the MemoryStream will be disposed of.
Let me copy your code and add some comments:
public byte[] ByteArraySerialize()
{
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(m))
{
writer.Write((int)this.Opcode);
writer.Write(this.Data);
}
// m is really disposed here
return m.ToArray();
}
}
Does this make a difference? Well, no. In the current implementation, disposing of the memory stream will not in any way trash it. But there is nothing guaranteed about the current implementation or its future, this is undocumented behavior. If you want this code to be stable and trustworthy for future versions or hotfixes to .NET, I would not write it like this.
As such, I would not use this way of doing it. I would rewrite the code as follows:
using (MemoryStream m = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(m))
{
writer.Write((int)this.Opcode);
writer.Write(this.Data);
writer.Flush();
return m.ToArray();
}
This will ask the writer to flush all the data, and then you make a copy of the internal array of the memory stream, before that instance is disposed.
Either that, or use the overloaded constructor and ask the writer to leave the stream open:
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(m, Encoding.UTF8, true))
{
writer.Write((int)this.Opcode);
writer.Write(this.Data);
}
// m is no longer disposed here
return m.ToArray();
}
The call to ToArray(); effectively makes a copy of the data you want.
So everything and anything happening to the MemStreams is irrelevant.
More generally, as long as your code can 'see' a piece of data then the GC can't recycle that piece.
Don't overthink this.
Suppose you had used:
return m.GetBuffer();
Now you are returning the internal buffer of the MemStream. m will be Disposed but simply because you returned it, the buffer will outlive its owner.
I think the answer to your question is "Not in this case".
The memory stream could of course be disposed, however before that you'll have your data in byte[] array, which will stay.
Try adding writer.Flush(); just after your writer.Write(this.Data);.
No, there is no problem. The stream will not be disposed too early.
You talk about the GC, but the idea with using statements and IDisposable is that any resource will freed immediately when the object goes out of scope. We won't have to wait for the GC. In other words this has no relation to the GC.

BitmapPalette Insufficient memory exception

I have the following piece of code that runs in a loop.
public void Test(Bitmap bmp)
{
FormatConvertedBitmap fBitmapSource = new FormatConvertedBitmap();
PngBitmapEncoder pngBitmapEncoder = new PngBitmapEncoder();
BitmapImage bi = new BitmapImage();
using (MemoryStream ms = new MemoryStream())
{
bmp.Save(ms, ImageFormat.Png);
bmp.Dispose();
bmp = null;
bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
BitmapPalette pallete = new BitmapPalette(bi, 256);
...
Last line
BitmapPalette pallete = new BitmapPalette(bi, 256);
Sometimes throws the following exception
Insufficient memory to continue the execution of the program.at System.Windows.Media.Imaging.BitmapPalette..ctor(BitmapSource bitmapSource, Int32 maxColorCount)
Any ideas ? I clearly have enough memory to continue execution.
There are other sources of OutOfMemoryException in a managed program that don't have anything to do with running out of managed memory. The exception is also raised when it translates error codes returned by legacy native code. Like the E_OUTOFMEMORY error that can be returned by COM method calls. And relevant in your case, by GDI+. Which has only 20 distinct error codes to indicate failure, you'll find them documented in this answer. One of them is OutOfMemory.
Which can mean more than one thing. Running out of unmanaged memory, the kind used by GDI+ to store bitmap pixels is certainly a possibility. It can also mean that your process has run out of available GDI object handles, Windows imposes a handle quota of 10,000 GDI handles. Which is an enormous number btw, exceeding that quota almost always indicates a bug in the code. A handle leak. Which in the case of a managed program is almost always caused by forgetting to use the Image.Dispose() method and not having the garbage collector run often enough to allow the finalizer to release handles.
Sadly it can even be triggered by corrupted bitmap data, not likely in your case since you bomb on allocating the palette. Which indicates a handle leak, which ought to be readily visible in Taskmgr.exe, Processes tab. View + Select columns and tick GDI Objects. Keep an eye on the displayed value for your process while you test it. A steadily increasing number spells trouble, the show is over when it reaches 10,000. Also look at the "Commit size" column, that can show you trouble with consuming too much unmanaged memory.

out of memory exception when use control.BackgroundImage = Image.FromStream(memStream);

I write a code that read a png image from file and show with control.
I want read image from stream and set
control.BackgroundImage = Image.FromStream(memStream);
but when use this code , occur "out of memory" exception. but when use
control.Image = Image.FromStream(memStream);
or
control.BackgroundImage = Image.FromFile(fileSource);
, that is work.
image file size is 5KB.
if (System.IO.File.Exists(imgSource))
{
using (FileStream localFileStream = new FileStream(imgSource, FileMode.Open))
{
using (MemoryStream memStream = new MemoryStream())
{
int bytesRead;
byte[] buffer = new byte[1024];
while ((bytesRead = localFileStream.Read(buffer, 0, buffer.Length)) > 0)
{
memStream.Write(buffer, 0, bytesRead);
}
retIMG = Image.FromStream(memStream);
pictureBox1.Image = retIMG; // is work
label1.Image = retIMG; // is work
button1.Image = retIMG; // is work
button1.BackgroundImage = retIMG; // don't work
groupBox1.BackgroundImage = retIMG; // don't work
panel1.BackgroundImage = retIMG; // don't work
}
}
}
I think a bug in .net framework.
please you help me?
Read the remarks on Image.FromStream on MSDN:
You must keep the stream open for the lifetime of the Image.
So if you remove the using around the creation of your MemoryStream your code works fine.
Of course you should preferrably dispose the MemoryStream once you no longer need the Image you created, although there is likely no harm in this case in not calling Dispose() and leaving it up to the GC to collect it once unused.
The fact that it seems to work with some of your code is likely pure luck and should not be considered a working solution. Always read the documentation to find out about quirks like this.
Giving some background to add to DeCaf's correct answer. GDI+ tries very hard to avoid copying the pixels of a bitmap. That's expensive, bitmaps taking dozens of megabytes is not unusual. When you load a bitmap from a file with the Bitmap constructor or Image.FromFile() then GDI+ creates a memory-mapped file. The pixels are paged-in on demand, only when needed. Very efficient but it puts a lock on the file. Clearly you were trying to avoid that in lock in this code.
You indeed avoid that lock by loading the bytes into memory yourself with a MemoryStream. But the same principle still applies, GDI+ still doesn't copy the pixels and only reads from the stream when it needs to. This goes wrong when you Dispose() the stream. Very hard to diagnose because the exception occurs later, typically when the bitmap needs to be drawn. It bombs in the painting code, you don't have any code to look at but Application.Run(). With a crappy exception message, GDI+ only has a handful of error codes. You are not out of memory, it only looks that way to GDI+, it cannot otherwise figure out why the stream suddenly isn't readable anymore.
At least part of the problem is caused by the very awkward implementation of MemoryStream.Dispose(). Dispose is meant to release unmanaged resources. A memory stream doesn't have any, it only owns memory. That's already taken care of by the garbage collector. Unfortunately they implemented it anyway. Not by actually disposing anything, since there's nothing to dispose, but by marking the MemoryStream unreadable. Which triggers the error in GDI+ when it tries to read while drawing the bitmap.
So simply remove the using statement to avoid disposing the MemoryStream to solve your problem. And don't fret about disposing it later when the bitmap is no longer in use. There's nothing to dispose, the garbage collector automatically frees the memory.
Two things which together resolved this intermittent issue, which has nothing to do with image size.
First, ensure that the image is in RGB mode and definitely not CMYK mode. In our experience, the RGB rendering is actually larger.
Second, erase (and dispose of if possible) any previous image in the image container before loading the new image, such as
Control.Image = Nothing

Categories