tags:

views:

133

answers:

2

When loading an image into memory, does .Net use DDB, DIB, or something else entirely? If possible, please cite your sources.

I'm wondering because we currently have a classic ASP application that is using a 3rd party component to load images that is occasionally creating a “Not enough storage is available to process this command.” error. The error is very inconsistent but tends to happen on larger images (not always, but often). After resetting IIS, processing the same file again typically works just fine.

After much research I have found that DDBs tend to have this problem when processing large images because they work out of video memory. Considering that we are running on a web server with an integrated video card and limited shared memory, this could certainly be our problem.

We are in the early stages of converting our app to .Net and am wondering if using .Net for this might be a viable alternative to our current method which is why I am asking the question.

Any advice is welcome :) but out of curiosity if nothing else, I am really hoping for an answer to the question; does .Net use DDB or DIB?

+3  A: 

Disclaimer: my answer is possibly relevant only to pre-WPF .NET (but the same concepts apply to both).

The answer to your headline question is "both". The System.Drawing namespace includes a handy Bitmap class that is essentially a DIB (or Device Independent Bitmap). The Bitmap class includes a GetHbitmap method which creates a DDB (or Device Dependent Bitmap) in-memory copy of the original DIB and returns a handle to it.

The DDB handle can be selected into a device context (which lets you use the super-fast BitBlt API method). Or you can just never create a DDB in the first place, and do all of your graphics operations with pure .Net (the best way, IMO). GetHbitmap is a relatively dangerous method, as you have to call DeleteObject on the handle it returns in order to free up its memory when you're done with it (it's the only example I can think of where a .Net method requires a PInvoked API call in order to function correctly). Also, because the method returns an IntPtr, programmers tend not to realize that when it's called the OS has to carve out another chunk of memory equal in size to the original .Net (DIB) bitmap.

So the answer is: .Net uses DIBs, but can use DDBs if necessary. Or worse, when not necessary. I've actually inherited more than one .NET web app that used GetHBitmap without the matching DeleteObject call, producing one long memory leak.

You have a broader question, though, which is: can a .Net application running on a server reliably process a large volume of large image files without crashing the server? The answer is yes, so long as you really understand what the .NET framework is doing under the hood with image manipulation. .NET graphics classes encapsulate a lot of the grisly details away from the programmer, and some ways this is kind of bad because it makes it less likely that a programmer will learn what's really going on.

Edit: forgot to include this important disclaimer from MSDN:

Caution

Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions.

Translation: "you're probably going to screw this up - don't say we didn't warn you". It's fundamentally sound advice, because these classes - while very powerful and utile - are also dangerous. It's extremely easy to consume some resource and fail to release it properly, or to use the classes in a way that results in massive memory consumption. Sometimes these problems are not large in a desktop application, but in a heavily-loaded web server serving multiple requests simultaneously it can become a huge problem.

I think they can be used safely in this context, however, or to put it a little differently, I think they can be used as safely as anything else if you're trying to process a large number of sizable bitmaps on a web server at the same time. However, I would make certain that I heavily load-tested my web site code before going live to production.

Update 1: The following quote (with link) applies to bitmaps in the .NET Compact Framework, and I do not think it applies to the full framework (I'm mainly including it here for general reference - i.e. so I can find it again myself someday):

Here is a little deeper information on the way [.NetCF] Bitmaps may be allocated. There are two major paths for allocation which may affect where the memory is allocated, but in the end have the same issues as indicated above.

  1. Bitmap constructor that takes a stream as a parameter [i.e. loads from a file]
    • This will construct a DIB
    • DIBs are allocated out of the application process virtual memory (VM) address space
  2. Bitmap constructor that takes a height/width as parameters
    • This will construct a DDB
    • DDBs are allocated by the driver, typically, in the gwes.exe or possibly in dedicated video RAM. This will actually use physical and virtual memory that is not in the process VM space.

In short, we have 2 different types of Bitmap in our runtime with varying performance and allocation characteristics. DDBs are generally faster to manipulate and draw to the screen than DIBs, but they are constructed in an external memory space that can cause allocation confusion and cause the performance of calls to LockBits or Save to be slower. If a DIB is desired and you wish to construct it based on width and height, we provide a function that constructs a Bitmap with a width, height, and pixelformat specified. This function will construct a DIB instead of a DDB.

More information (still just on .NetCF bitmaps) here:

http://blog.opennetcf.com/ctacke/PermaLink,guid,987041fc-2e13-4bab-930a-f79021225b74.aspx

Update 2: some links relevant to .NET bitmaps in the full framework (summary at the bottom):

http://www.dotnetmonster.com/Uwe/Forum.aspx/dotnet-performance/1187/Graphics-FromImage-Process-memory-usage

http://www.netframeworkdev.com/common-language-runtime/memory-issues-with-systemdrawingbitmap-30879.shtml

http://www.west-wind.com/WebLog/posts/8230.aspx

http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.drawing/2005-06/msg00171.html

Summary: I think this question is difficult to answer because, basically, this (the actual location of the memory used by Bitmap) is an internal .NET implementation detail, mostly undocumented for a good reason. Since it appears that you can't really be sure where the bitmap's memory lives right now, and you definitely can't be sure where it will live in the future, I'd have to say MSDN probably wasn't kidding when they said:

Caution

Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions.

MusiGenesis
Can you cite your references for how .Net manages images? I wasn't able to find this information but it's got to be available somewhere. I would like to learn more about it.
Brian
"Or you can just never create a DDB in the first place, and do all of your graphics operations with pure .Net (the best way, IMO)." -- safe but s.................l...........................o...................w
Windows programmer
Just to clarify, that means s................l...................o....................w.
Windows programmer
@Brian: I just re-read your question and realized that I didn't really answer it. I will find a ref or two on this - my own knowledge is semi-jumbled between Windows and Windows Mobile.
MusiGenesis
@Windows programmer: **is not.** :)
MusiGenesis
You did answer his question. .Net uses both, and he can use .Net, but he should avoid the parts that use DDBs because they eat graphics RAM and he should carefully benchmark the parts that use DIBs because if he's not careful they'll be S..........L...............O....................W.
Windows programmer
@Windows programmer: see? You're already weakening in your certainty here. Now we're up to capital letters and fewer dots and qualifiers like "if he's not careful ...". I'll just wait and eventually you'll make my point for me, which is that it's *possible* to do nice, speedy graphics in pure .NET (as long as you still count the `unsafe` tag as "pure .NET"). :)
MusiGenesis
@Windows programmer: also, the question asker seemed primarily to be asking whether .NET graphics classes use general .NET process memory or Video RAM (the former being more available than the latter). I suspect there are some situations where .NET bitmaps *do* use video RAM (I know they use video RAM in some circumstances in Windows Mobile).
MusiGenesis
Unfortunately this API has been around for a long time, so it predates SafeHandle. I suppose you could re-declare the same PInvoke call in a class of your own and make a SafeBitmapHandle : SafeHandleZeroIsInvalid type to be sure you call DeleteObject, if you really needed to. Otherwise, for pretty much all purposes, remembering to call DeleteObject when you are done should be plenty safe enough.
Doug McClean
@Doug: I think the reasons behind not using System.Drawing in a service application go a lot deeper than just dealing with the bitmap handle.
MusiGenesis
@MusiGenesis. Definitely. Far, far beyond and perhaps even into another galaxy. But since that's the only way the IntPtr version is "less safe", and even ignoring the CriticalFinalizer you would still at least have a finalizer in case a caller messed up and you didn't DeleteObject something you allocated on their behalf, and it isn't that hard to do, it might still be useful for someone depending on their exact needs.
Doug McClean
+1  A: 

After much research, I have determined that although the System.Drawing namespace is not supported, it will probably work for many people (probably not for us due to the high volume of images manipulation that we do).

However, what is supported is Windows Imaging Components, however it is not managed code though they do provide a thin .Net wrapper around the Win32 calls. Bertrand Le Roy's blog has an article on how to use it: The fastest way to resize images from ASP.NET. And it’s (more) supported-ish. WIC seems to be significantly faster than GDI+.

Bertrand also covers how to manipulate images uses WPF, which is not supported but uses WIC, seems to perform on par with direct WIC, and is probably easier to code. The article for that is: Resizing images from the server using WPF/WIC instead of GDI+

Both WIC and WPF require full trust so if you are working in a medium trust environment, you will be stuck with GDI+.

Brian
If you're in a medium trust environment, you won't be able to use the `unsafe` keyword, which allows direct access to the `Bitmap`'s pixel data through the LockBits method, although this would only matter if you were trying to do pixel-by-pixel manipulation.
MusiGenesis