Dear Sir,
I just try to write very simple code to create Bitmap file
"Bitmap b = new Bitmap (16500, 12500, PixelFormat.Format24bppRgb);"
But I got Error Message "ArgumentException was Unhandled. Parameter is not valid"
My PC got 2 GB Ram and at the time it still available for 1.2 GB. From above image size,
it should use only 16500*12500*3 = 618,750,000 byte.
I don't know what it's wrong. Or it have such limitation on this syntax.
Please kindly help to advice.
Anusron W.
Loading
VulpesPosted Jul 18, 2011, 5:28 AM
Zoran HorvatPosted Jul 17, 2011, 7:16 PM
GC.GetTotalMemory Method
Retrieves the number of bytes currently thought to be allocated.
The same sentence is also popped up by intellisense when you try to type GC.GetTotalMemory, making coders think wrong every time they call this method. Now it is clear that it should say: Retrieves the number of bytes currently thought to be allocated on managed heap. For example in Pro C# 2008 the author defines GetTotalMemory method much more precise: Returns the estimated amount of memory (in bytes) currently allocated on the managed heap.
That would explain why GDI memory does not count. This is an example how MSDN fails to define .NET good enough which in turn produces misunderstandings in code.
There is one more thing that crossed my mind. Again I'm turning back to a misleading ArgumentException. Much better choice would be System.InsufficientMemoryException, which is normally thrown before operation is conducted which is known in advance to end up in OutOfMemoryException. So it would be more informative if Bitmap constructor just threw InsufficientMemoryException when too large a bitmap was attempted to be created.
Zoran
VulpesPosted Jul 17, 2011, 6:54 PM
Zoran HorvatPosted Jul 17, 2011, 5:38 PM
using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
bool failed = false;
int width = 1000;
while (!failed)
{
try
{
Bitmap b = new Bitmap(width, 1000, PixelFormat.Format24bppRgb);
Console.WriteLine("Passed with {0} megapixels (allocated {1} megabytes; bitmap size: {2}x{3})", width / 1000, GC.GetTotalMemory(false), b.Width, b.Height);
width *= 2;
}
catch (System.Exception ex)
{
Console.WriteLine("Failed for {0} megapixels", width / 1000);
Console.WriteLine(ex);
failed = true;
}
}
Console.ReadLine();
}
}
}
It allocates larger and larger bitmaps, tracking memory consumption and exceptions. At the same time, I'm ensuring that bitmap (variable b) is not garbage collected by printing its dimensions. And this is the output on my computer (which has 4 GB of RAM, by the way):
Passed with 1 megapixels (allocated 186836 megabytes; bitmap size: 1000x1000)
Passed with 2 megapixels (allocated 195028 megabytes; bitmap size: 2000x1000)
Passed with 4 megapixels (allocated 195028 megabytes; bitmap size: 4000x1000)
Passed with 8 megapixels (allocated 195028 megabytes; bitmap size: 8000x1000)
Passed with 16 megapixels (allocated 195028 megabytes; bitmap size: 16000x1000)
Passed with 32 megapixels (allocated 195028 megabytes; bitmap size: 32000x1000)
Passed with 64 megapixels (allocated 195028 megabytes; bitmap size: 64000x1000)
Passed with 128 megapixels (allocated 195028 megabytes; bitmap size: 128000x1000)
Failed for 256 megapixels
System.ArgumentException: Parameter is not valid.
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
at ConsoleApplication.Program.Main(String[] args) in ...
What seems odd here is that memory consumption does not grow, not even as memory pressure. That last part is also very suspicious because memory consumption of the process grows as new larger instances of bitmap are allocated. This indicates that Bitmap class does not add memory pressure to the GC, which probably has something to do with memory management under Windows - like GDI-consumed memory does not count into whatever other objects count in. Anyway, I would expect that memory to be included in GC's count but it is not.
When I made a change to the code, by just doing b.Dispose() after the status printout, the result was that it has failed one step further, when trying to allocate 512 millions of pixels in bitmap, which is consistent with the fact that memory consumption was the cause of the problem.
What remains a bit of mistery is this: why would Bitmap constructor throw argument exception instead of OutOfMemory exception. Maybe because it did not run out of memory, but only would run out of memory should it really create the bitmap as requested. Another question is why MSDN says nothing about this case. For .NET Framework 4 they only say this:
ArgumentException - A PixelFormat value is specified whose name does not start with Format. For example, specifying Gdi will cause an ArgumentException, but Format48bppRgb will not.
So the result seems to be this - Bitmap constructor fails if its execution would lead to out of memory condition or something similar (maybe out of handles has the same effect, ect.).
Zoran
VulpesPosted Jul 17, 2011, 8:14 AM
Anusorn WPosted Jul 17, 2011, 7:25 AM
Thanks for your kindly reply my issue.
I'm very sure this error message came out from this line and I tried to do as your suggestion.
And I got message as following.
System.ArgumentException: Parameter is not valid.
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
at AOI_Solution0.OpenJob.btnOpen_Click(Object sender, EventArgs e) in D:\Bluezens\Document\Software Application\AOI SOLUTION0 V1.506 Add Setup Project1\AOI_Solution0\AOI_Solution0\OpenJob.cs:line 238
And I would like to know how is your system memory size. I'm not so sure whether it related to this matter or not.
As above Line 238 is syntax to create Bitmap which I got error message.
Please kindly give more advice to me once again.
Regards
Anusorn W.
Zoran HorvatPosted Jul 17, 2011, 5:02 AM
This statement works fine on my computer. Are you sure that this is the precise line on which exception was raised? Also, if you wrap this line in try-catch block, is there an inner exception that could give more information? Something like this:
try
{
Bitmap b = new Bitmap(16500, 12500, PixelFormat.Format24bppRgb);
}
catch (System.Exception ex)
{
Console.WriteLine(ex);
if (ex.InnerException != null)
Console.WriteLine("Inner exception: {0}", ex.InnerException); // This will also be present in WriteLine(ex) above
}
Zoran