How to dispose of a PrivateFontCollection correctly? - c#

I'm using PrivateFontCollection to install uploaded fonts on my web server. The code below works, but on second upload of a font the PrivateFontCollection references the first font uploaded. So something isn't being disposed of correctly. Anyone spot what I'm doing wrong?
var fontName = string.Empty;
using (var ms = new MemoryStream(fontBytes))
{
// used to store our font and make it available in our app
using (var pfc = new PrivateFontCollection())
{
//create memory pointer
IntPtr data = Marshal.AllocCoTaskMem((int)ms.Length);
try
{
//copy the bytes to the unsafe memory block
Marshal.Copy(fontBytes, 0, data, (int)ms.Length);
// We HAVE to do this to register the font to the system (Weird .NET bug !)
uint cFonts = 0;
AddFontMemResourceEx(data, (uint)fontBytes.Length, IntPtr.Zero, ref cFonts);
//pass the font to the font collection
pfc.AddMemoryFont(data, (int)ms.Length);
var fontWithMime = "data:application/x-font-truetype;charset=utf-8;base64," + cleanFontData;
fontName = pfc.Families[0].Name;
//db work here
}
finally
{
ms.Close();
Marshal.FreeCoTaskMem(data);
}
}
}

PrivateFontCollection is a very flawed class and you have to be extremely careful using it. A very gross bug in your existing code is the Marshal.FreeCoTaskMem() call. It is up to you to ensure that you do not call this function until after your code stops using any Font object you created from the family. Failure to do so causes random glyph corruption, you only get an AccessViolationException if you are lucky. Underlying problem is that the font will continue to use the memory you allocated with AllocCoTaskMem(), it is completely unaware that the memory is no longer valid. Corruption occurs when the memory is re-used.
Furthermore, while the class has an AddMemoryFont() method, it does not have a corresponding RemoveMemoryFont() method. The only way to clean up is by calling PrivateFontCollection.Dispose(). This deletes all of the fonts in the collection. With the same stipulation as in the previous paragraph, you can only call Dispose() when you are sure that you no longer use any Font object. Calling it too early does not cause an exception.
Very awkward behavior, only truly safe way to use the PFC is to keep it around for the life of the app. Pretty painful in a web app of course.
You can assume that the added font is the last one in the FontFamily[] array. Not the first one as you have it implemented now.

According to AddFontMemResourceEx function:
To remove the fonts that were installed, call RemoveFontMemResourceEx.
However, when the process goes away, the system will unload the fonts
even if the process did not call RemoveFontMemResource.
However, I don't see you doing that. That might be the reason.

Related

C# Possible Memory Leak?

So, I have an app, written in C# (vs2010), performing OCR using the tesseract 3.02 dll and Charles Weld's terreract .net wrapper.
I think I have a memory leak and it seems to be in the area of code where the Pix object is allocated. I am taking a PDF, converting that to a grayscale PNG, then loading that into a Pix object for OCR. When it works, it works really well. Image is large in size (5100 or so pixels in each dim) but not so large in size (only 500k or so).
My code:
Init engine at app startup:
private TesseractEngine engine = new TesseractEngine(#"./tessdata/", "eng+fra", EngineMode.Default);
Method to convert PDF to PNG, then calls:
// Load the image file created earlier into a Pix object.
Pix pixImage = Pix.LoadFromFile(Path.Combine(textBoxSourceFolder.Text, sourceFile));
And then calls the following:
// Perform OCR on the image referenced in the Pix object.
private String PerformImageOCR(Pix pixImage)
{
int safety = 0;
do
{
try
{
// Deskew the image.
pixImage = pixImage.Deskew();
//pixImage.Save(#"c:\temp\img_deskewed.png", ImageFormat.Png); // Debugging - verify image deskewed properly to allow good OCR.
string text = "";
// Use the tesseract OCR engine to process the image
using (var page = engine.Process(pixImage))
{
// and then extract the text.
text = page.GetText();
}
return text;
}
catch (Exception e)
{
MessageBox.Show(string.Format("There was an error performing OCR on image, Retrying.\n\nError:\n{0}", e.Message), "Error", MessageBoxButtons.OK);
}
} while (++safety < 3);
return string.Empty;
}
I have observed that memory usage jumps by about 31MB when the Pix object is created, then jumps again while OCR is being performed, then finally settles about 33MB higher than before it started. ie: if app, after loading, was consuming 50MB, loading the Pix object causes the memory usage to jump to about 81MB. Performing OCR will see it spike to 114+MB, then, once the process is complete and the results saved, the memory usage settles to about 84MB. Repeating this over many files in a folder will eventually cause the app to barf at 1.5GB or so consumed.
I think my code is okay, but there's something somewhere that's holding onto resources.
The tesseract and leptonica dlls are written in C and I have recompiled them with VS2010 along with the latest or recommended image lib versions, as appropriate. What I'm unsure of, is how to diagnose a memory leak in a C dll from a C# app using visual studio. If I were using Linux, I'd use a tool such as valgrind to help me spot the leak, but my leak sniffing skills on the windows side are sadly lacking. Looking for advice on how to proceed.
Reading your code here I do not see you disposing your Pix pixImage anywhere? That's what is taking up all the resources when you are processing x images.
Before you return your string result you should call the dispose method on your pixImage. That should reduce the amount of resources used by your program.
I'm not familliar with Tesseract or the wrapper, but for memory profiling issues, if you have Visual Studio 2012/2013, you can use the Performance Wizard. I know it's available in Ultimate, but not sure on other versions.
http://blogs.msdn.com/b/dotnet/archive/2013/04/04/net-memory-allocation-profiling-with-visual-studio-2012.aspx
It's either something in your code or something in the wrapper is not disposing an unmanaged object properly. My guess would be it's in the wrapper. Running the Performance Wizard or another C# memory profiler (like JetBrains DotTrace) may help you track it down.

C# "Out Of Memory Exception" on returning variable accessor

I am getting an Out Of Memory Exception when I attempt to new a Bitmap and return it through a "get" accessor. The Bitmap is of size 640x480 with depth Int32.
My suspicion is that the C# Garbage Collector is unable to delete these old Bitmaps because they are being returned in the accessor to my variable. I have well over 2GB available so I wouldn't imagine that this "small" image is taking up too much memory. Unfortunately I HAVE to new the Bitmap due to thread locking issues (Trouble with locking an image between threads) The code is as follows:
public Bitmap LiveFrame { get { return GetFrame(500); } }
.....
private Bitmap GetFrame(int timeout)
{
Bitmap ret = null;
//CLEyeCameraGetFrame places image data into this._PrivateBitmap
bool success = CLEyeCameraGetFrame(_Camera, _PtrBmpPixels, timeout);
if(success)
ret = new Bitmap(this._PrivateBitmap);
return ret;
}
Note on unmanaged code:
CLEyeCameraGetFrame is in an unmanaged DLL. I allocate _PtrBmpPixels using Marshal.AllocHGlobal earlier in the code and don't touch it until freeing when closing the app. _PtrBmpPixels was used in the creation of the Bitmap _PrivateBitmap through its constructor that accepts the IntPtr argument "scan0". Thus, whenever _PtrBmpPixels is updated via CLEyeCameraGetFrame, _PrivateBitmap is also updated.
I attempted to fix this by Disposing the PcitureBox Bitmap before reusing it, but that broke the PictureBox display. I have two threads updating two different PictureBox/ImageBoxes:
lock (_CameraLocker)
{
if (_VideoPlaying)
{
try{
if (pbLiveFeed.Image != null)
pbLiveFeed.Image.Dispose();
pbLiveFeed.Image = _Camera.LiveFrame;
pbLiveFeed.Invalidate();
}catch (Exception ex) { }
}
....
lock (_CameraLocker)
{
try{
if (ibProcessed.Image != null)
ibProcessed.Image.Dispose();
procImage = new Image<Bgra, Int32>(_Camera.LiveFrame);
procImage.Draw(new Rectangle(10, 20, 20, 15), new Bgra(1.0, 1.0, 1.0, 1.0), 5);
ibProcessed.Image = procImage;
}catch (Exception ex) { }
}
Could Garbage collection be the cause of this? Is it not safe to return a newed object from a get accessor?
The only real clue in your question is in what is missing. You never said "and I make sure to dispose the bitmap after using it". Which is something you can overlook easily in .NET programming but will come to byte you when you use bitmaps.
The Bitmap class is a very small wrapper class around an unmanaged resource created by GDI+. The actual bitmap pixels are stored in unmanaged memory. Which is why the class has a Dispose() method, that releases the unmanaged memory allocation. The garbage collector can do little to help you get this memory released automatically, a Bitmap object is too small to induce a garbage collection often enough to keep up with the rate at which your program consumes unmanaged memory. An oom-kaboom is the outcome.
You'll need to look at the rest of your code and see how the LiveFrame property is getting used. And make sure that the returned bitmap is getting disposed. If, say, you assign it to a PictureBox.Image property then you have to dispose the old image before assigning it.

OutOfMemoryException handling and Windows Media Player SDK

How it must work:
WindowsMediaPlayer windowsMediaPlayer = new WindowsMediaPlayer();
IWMPMediaCollection collection = windowsMediaPlayer.mediaCollection;
IWMPMedia newMedia = collection.add(path); //causes OutOfMemoryException after some thousands method's iterations
I've tried to avoid it this way:
try
{
newMedia = collection.add(path);
return newMedia;
}
catch (Exception)
{
collection = null;
GC.Collect();
GC.WaitForPendingFinalizers();
WindowsMediaPlayer windowsMediaPlayer = new WindowsMediaPlayer();
IWMPMediaCollection collectionNew = windowsMediaPlayer.mediaCollection;
return CreateNewMedia(collectionNew, path);
}
But this does not work – I still get infinite exception loop inside catch.
You can not handle OutOfMemoryException like ordinary one. The reason you may have handling that, is just, in some way, to save the state of application, in order to provide to the consumer of your application a way to recover lost data.
What I mean is that there is no meaning calling GC.Collect or whatever, cause application is going to dead anyway, but CLR kindly give you notification about that before.
So to resolve this issue, check the memory consumption of your application, that on 32bit machine has to be something about 1.2GB of RAM, or control the quantity of the elements in collections you have, that can not exceed, for ordinary list, 2GB of memory on 32bit and on 64bit too.

Is passing System.Drawing.Bitmap across class libraries unreliable?

I have a 3rd party dll which generates a Bitmap and send back its reference. If I generate a System.Windows.Media.Imaging.BitmapSource out of it immediately then all goes well. But if I save the reference and later on (after a few seconds and many function calls) I try to generate the Bitmapsource, I get
System.AccessViolationException was
unhandled by user code
Message=Attempted to read or write
protected memory. This is often an
indication that other memory is
corrupt. Source="System.Drawing"
when doing :
System.Windows.Media.Imaging.BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
bmp.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
Any clues on whats going wrong here ? Any pointers will be useful. Thanks.
I think this indicates that the handle (reference to a resource managed by the operating system, rather than .Net) returned by bmp.GetHBitmap is no longer valid - possibly a Dispose has been called somewhere or something like that (not necessarily by your code though).
I'd recommend using another way of persisting the bitmap data that does not rely on handles - possibly stream out the binary data of the bitmap itself immediately, and then throw a reference to that around.
I had a big problem with Bitmaps and access violations as well. What I believe to be happening is that certain bitmap constructors leave file handles open when they should not. Thus, the program you are running detects that the files are in use, when they shouldn't be.
I eventually figured out a solution in that I make a copy of the original bitmap and then dispose the original. Here is my code, which preserves the resolution of the original Bitmap:
Bitmap Temp = new Bitmap(inFullPathName);
Bitmap Copy = new Bitmap(Temp.Width, Temp.Height);
Copy.SetResolution(Temp.HorizontalResolution, Temp.VerticalResolution);
using (Graphics g = Graphics.FromImage(Copy))
{
g.DrawImageUnscaled(Temp, 0, 0);
}
Temp.Dispose();
return Copy;
Obviously, for the first line, yours would be Bitmap Temp = MyThirdPartyDLL.GetBitmap(); or something. If you don't care about the resolution it can be simplified to:
Bitmap Temp = MyThirdPartyDLL.GetBitmap();
Bitmap Copy = new Bitmap(Temp, Temp.Width, Temp.Height);
Temp.Dispose();
return Copy;
After making this change, I was able to do all kinds of File I/O, etc, perfectly fine, hope you can do the same.

GDI+ exception saving a Bitmap to a MemoryStream

I have a problem in a Windows Forms application with Bitmap.Save failing when I save to a MemoryStream. The problem only seems to occur intermittently on one machine (so far) and the bad news it is at a customer site. I can't debug on the machine, but I got a stack trace that narrowed the problem down to a single line of code.
Here's a condensed version of my code:
byte[] ConvertPixelsToBytes()
{
// imagine a picture class that creates a 24 bbp image, and has
// a method to get an unmanaged pixel buffer.
// imagine it also has methods for getting the width,
// height, pitch
// I suppose this line could return a bad address, but
// I would have expected that the Bitmap constructor would have
// failed if it was
System.IntPtr pPixels = picture.GetPixelData();
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(
picture.width(),
picture.height(),
picture.pitch(),
System.Drawing.Imaging.PixelFormat.Format24bppRgb,
pPixels );
// This line doesn't actually free the memory, but it could be freed in a
// background thread
// (2)
picture.releasePixelData(pPixels);
System.IO.MemoryStream memStream = new System.IO.MemoryStream();
try
{
// I don't see how this line could fail, but it does
// (3)
bmp.Save(memStream, System.Drawing.Imaging.ImageFormat.Bmp);
return memStream.ToArray();
}
catch(System.Runtime.InteropServices.ExternalException e)
{
// e.Message is the very helpful " A generic error occurred in GDI+."
}
finally
{
memStream.Dispose();
}
return new byte[0];
}
Any idea what might be going on? I'm pretty sure my pixel buffer is right, it always works on our dev/test machines and at other customer sites.
My thoughts on possible reasons for failure are
a. The bitmap constructor doesn't copy the pixel data, but keeps a reference to it, and the Save fails because the memory is released. I don't find the MSDN docs clear on this point, but I assume that the Bitmap copies the pixel data rather than assume it is locked.
b. The pixel data is invalid, and causes the Save method to fail. I doubt this since my pixel data is 24 Bits per pixel, so as far as I know it should not be invalid.
c. There's a problem with the .NET framework.
I would appreciate any thoughts on other possible failure reasons so I can add extra checks and logging information to my app so I can send something out into the field.
The MSDN docs for that Bitmap constructor leave no doubt whatsoever:
Remarks
The caller is responsible for allocating and freeing the block of memory specified by the scan0 parameter, however, the memory should not be released until the related Bitmap is released.
Have you tried moving
picture.releasePixelData(pPixels);
to
finally
{
memStream.Dispose();
picture.releasePixelData(pPixels);
}
it definitely sounds like a threading issue (especially since you state that the releasePixelData could happen on a background thread). Threading issues are always the ones that only happen on one machine, and it is always on the clients machine (probably due to the fact they only have 256Megs of memory or something ridiculous and garbage collector is kicking in early, or the machine has quad core and your developer machine is dual core or something).

Categories

Resources