12

An ASP.NET application on my server starts throwing GDI+ exception after running for several days. After I restart the server, all works fine for a couple of days and then suddenly this exception occurs again. After the first time it occurs, it occurs every time I try to save a PNG image, until I restart again.

When I try to save the image in JPEG, it works fine.

When I run this code from my project, it fails:

var path = @"C:\Project\images\logo.png";
var image = Image.FromFile(path);

using (var ms = new MemoryStream())
{
    image.Save(ms, ImageFormat.Png);     // Fails here on GDI+ exception.
    //image.Save(ms, ImageFormat.Jpeg);  // JPEG works somehow
}

Again: When I restart remote desktop and run this code, it works for a couple of days and at some moment suddenly starts to fail over and over.

I tried:

  1. To make a console application with the same code and run it in the RDP where the project is. It worked fine!

  2. Lots of different variations of codes that were suggested in more then 10 articles I read on this topic.

  3. GCI.Collect() – no help.

  4. Checked all the folders that has write permissions (maybe there is something with the IIS?).

  5. More.

I think that it should be some configuration that suddenly changes due to something and I can’t understand what can it be.

Palec
  • 12,743
  • 8
  • 69
  • 138
Misha Zaslavsky
  • 8,414
  • 11
  • 70
  • 116
  • Try using `Image img = Image.FromStream(new MemoryStream(File.ReadAllBytes(path)));`. See http://stackoverflow.com/questions/788335/why-does-image-fromfile-keep-a-file-handle-open-sometimes – Cecilio Pardo Aug 31 '16 at 23:00
  • The image format is not the real reason. More likely: You try to overwrite the original (png). See [here](http://stackoverflow.com/questions/37736815/overwrite-image-picturebox-in-c-sharp/37741101?s=1|5.7472#37741101) – TaW Sep 01 '16 at 07:16
  • 1
    So what's the exceptoin exactly? – Evk Sep 03 '16 at 15:01
  • 1
    Obviously if it only fails periodically for you, it is something transient that we are never going to be able to reproduce. You dont need any of that code though - if it is already PNG, saving does nothing. If you are trying to get the image as bytes, `File.ReadAllBytes()` is all you need – Ňɏssa Pøngjǣrdenlarp Sep 03 '16 at 15:02
  • I suspect we lack context. Are you doing something with this in a loop? If so, show something akin to the actual code. – Ňɏssa Pøngjǣrdenlarp Sep 03 '16 at 15:35
  • 2
    Are you disposing of the images that you load? And disposing of GDI resources in general? – usr Sep 03 '16 at 16:22
  • @Plutonix No loop, and that's all the code that cause this problem. And the effect is not immidiate, it takes some days to start throwing this GDI+ exception. I think it may be a permission issue in IIS that changes suddenly. – Misha Zaslavsky Sep 03 '16 at 16:58
  • You do this in async context? – TheZodchiy Sep 05 '16 at 13:11
  • @TheZodchiy No. – Misha Zaslavsky Sep 05 '16 at 16:27
  • There is a problem with Image.FromFile, which is discussed in the question I linked. Use ReadAllBytes and it will stop failing. – Cecilio Pardo Sep 05 '16 at 18:40
  • @CecilioPardo Maybe. I already did it 2 days ago. Let's wait some days and see if it fixed :) – Misha Zaslavsky Sep 06 '16 at 03:31
  • Does it work if you remove the using around the MemoryStream? You give something (a MemoryStream) to Image and then this something goes out of scope. You should tie the life of this something to the life of Image (in other words dispose the MemoryStream after the Image). I know it doesn't seem logical, or it looks like it could work, but GDI+ is touchy. – Simon Mourier Sep 06 '16 at 07:12
  • @SimonMourier I am not sure I understood you, but if I understood correct then I already tried it and no help. Can you write here some code to show what you meant? – Misha Zaslavsky Sep 06 '16 at 07:25
  • Actually, re-reading your question, I'm not sure my comment applies, if you're 100% sure the exception is really on the image.Save command, it's probably something else. Note GDI+ is not supported on the server. You could use WPF (it's not supported either but may work better), as described here: http://weblogs.asp.net/bleroy/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi – Simon Mourier Sep 06 '16 at 19:53
  • log the number of open handles. `Process.HandleCount` and see if your process is consuming handles and not releasing them. If it is, you start a process of elimination attempting to release them. You could also try process explorer from sysinternals to check how many open handles the process is consuming. – Jim Sep 08 '16 at 12:07

3 Answers3

9

After I restart the server all works fine for a couple of days and then suddenly this exception occurs and after the first time it occurs it will occur everytime I try to save the PNG image, until I will restart again.

Sounds like a memory leak to me. What .NET version is this compiled to? What server OS this running on?

You can start by enclosing your image in a using block:

var path = @"C:\Project\images\logo.png";
using (Image image = Image.FromFile(path))
{
    using (var ms = new MemoryStream())
    {
        image.Save(ms, ImageFormat.Png);
    }
}

This link I believe is relevant to your case.

Community
  • 1
  • 1
ZagNut
  • 1,431
  • 15
  • 20
3

It throw GDI+ error because one of your object not disposed, so better dispose used object.

If you are getting that error , then I can say that your application doesn't have a write permission on some directory.

GDI+ limits the height of an image to 65534

Always favor using the using statement. Which never forgets to dispose an object, even if the code throws an exception.

var path = @"C:\Project\images\logo.png";
using (Image image = Image.FromFile(path))
{
      using (var ms = new MemoryStream())
      {
            image.Save(ms, ImageFormat.Png); //fails here on GDI+ exception.
            //image.Save(ms, ImageFormat.Jpeg); //Jpeg Works somehow
      }
}

The FromFile method locks the file, so use the Image.FromStream() method for reading the image:

byte[] bytes = System.IO.File.ReadAllBytes(filename);
System.IO.MemoryStream ms = new System.IO.MemoryStream(bytes);
using (var ms = new MemoryStream())
{
      image.Save(ms, ImageFormat.Png); //fails here on GDI+ exception.
      //image.Save(ms, ImageFormat.Jpeg); //Jpeg Works somehow
}
0

Basically, if you have disposable objects... Dispose them ! Image is disposable and as bitmap does, it uses windows resources. If you do not dispose, the windows resources are not freed till you shut down your application. So you need to dispose any image instantiated.

Laurent Lequenne
  • 902
  • 5
  • 13