2

We have a test of NUnit tests that are suffering OutOfMemoryExceptions on a particular machine.

After investigation it seems that it is not a memory issue, but a Handle issue (we are allocating too many Bitmap objects and not releasing them).

The issue is, that this runs perfectly on a particular machine, while failing with this error on another one.

  1. Failing machine is a Hyper-V VM with Windows7 x64 (6 GB ram)
  2. Working Machine is a physical machine Windows XP (2 GB ram)

I know that the best solution would be to clean up the code to dispose of any Bitmap objects, but i am interested in knowing why do these 2 machines differ in behavior when executing the same code?

lysergic-acid
  • 19,570
  • 21
  • 109
  • 218
  • 1
    Well, the .NET framework may be the same, but the underlying OS isn't. Resources like bitmaps are still handled by the operating system. Windows 7 handles resources differently than Windows XP does, so it is not surprising that you get different results on different versions of Windows. – helb Sep 30 '13 at 13:33
  • The number of handles that can leak before Windows refuses to issue any more is configurable. Perhaps one of the machines is configured differently. – Eric Lippert Sep 30 '13 at 13:49
  • Thanks @eric. Do u know where this can be controlled from ? – lysergic-acid Sep 30 '13 at 14:20
  • @lysergic-acid: This is a question and answer site. Ask the question as a question! – Eric Lippert Sep 30 '13 at 15:11

2 Answers2

1

Read this: http://blogs.technet.com/b/markrussinovich/archive/2010/02/24/3315174.aspx

You will find a table of the differences between various versions of Windows with respect to GDI heap. Short answer: XP = 3Mb limit, Win7R2x64 = 20Mb limit. Free RAM doesn't matter, these are hard limits.

jlew
  • 10,491
  • 1
  • 35
  • 58
1

That's unlikely, Windows allows you to leak 10,000 handles before it gets cranky about the way your program behaves and refuses to let you allocate more. By then you've consumed massive amounts of virtual memory space for the pixel data in the bitmaps. Stored in unmanaged memory, the garbage collector is unaware of it. VM space that doesn't get released unless you call Dispose() or the garbage collector takes care of it by running the finalizer.

The GC doesn't typically get the job done, the Bitmap class is a very small object, not big enough to trigger a GC by itself. You'd have to allocate about 60,000 of them to trigger a GC. You'll never get there, you'll run out of VM space first unless the bitmaps are very small, handles next. Calling Dispose() is optional, but that stops being optional for bitmaps since the finalizer just can't get the job done in time.

The amount of RAM plays no role in this whatsoever, a .NET program always bombs on it not being able to find a hole in the VM address space that's big enough to fit the requested size. Also an issue with bitmaps, they tend to need big holes. It just takes a DLL that gets loaded at an awkward base address to cut a nice big hole into two. Otherwise a problem that's easily solved, just set the target platform of the program to AnyCPU. A test program has a configuration value for that. Works on that Win7 machine. But of course, that's not a valid reason to skip the Dispose() calls.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536