|
|
|
start date: Mon, 13 Aug 2007 11:11:41 -0700,
posted on: microsoft.public.dotnet.framework.drawing
back
| Thread Index |
|
1
vector
|
|
2
Bob Powell [MVP]
|
|
3
Doug Forster nobody@nowhere,com
|
|
4
vector
|
ArgumentException and OutOfMemoryException in Bitmap constructor
I'm trying to write a program that spins through a List collection of
Image objects and manipulates them. Unfortunately I keep encountering
exceptions where I don't understand why they're happening. I've
stripped down my app into a sample program that has the same flaws in
it.
The first exception happens in a loop where I create and add Bitmap
objects to a List. The message is "Parameter is not valid," and it
can be avoided by adding "PixelFormat.Format1bppIndexed" to the Bitmap
constructor.
The second exception is an out of memory error, where I'm trying in a
loop to create a deep copy of each Image object in the List,
manipulate it (but not in the sample code below), and replace the old
Image in the List with the new Image.
I really don't understand what's going wrong here. Can someone please
explain this to me?
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;
namespace ConsoleApplication2
{
class Program
{
[STAThread]
static void Main(string[] args)
{
try {
bool causeArgumentException = false;
bool causeOutOfMemoryException = true;
RunTest(causeArgumentException, causeOutOfMemoryException);
}
catch (ArgumentException ex) {
//A first chance exception of type 'System.ArgumentException'
occurred in System.Drawing.dll
// at System.Drawing.Bitmap..ctor(Int32 width, Int32 height,
PixelFormat format)
// at System.Drawing.Bitmap..ctor(Int32 width, Int32 height)
// at ConsoleApplication2.Program.RunTest(Boolean
causeOutOfMemoryException) in c:\source\ImagePro2008\ImagePro
\Class1.cs:line 49
// at ConsoleApplication2.Program.Main(String[] args) in c:
\source\ImagePro2008\ImagePro\Class1.cs:line 17
Debug.WriteLine(ex.StackTrace);
// Parameter is not valid.
Debug.WriteLine(ex.Message);
}
catch (OutOfMemoryException ex) {
// A first chance exception of type
'System.OutOfMemoryException' occurred in System.Drawing.dll
// at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
// at System.Drawing.Graphics.DrawImage(Image image, Int32 x,
Int32 y, Int32 width, Int32 height)
// at System.Drawing.Bitmap..ctor(Image original, Int32 width,
Int32 height)
// at System.Drawing.Bitmap..ctor(Image original)
// at ConsoleApplication2.Program.RunTest(Boolean
causeOutOfMemoryException)
// at ConsoleApplication2.Program.Main(String[] args)
Debug.WriteLine(ex.StackTrace);
// Out of memory.
Debug.WriteLine(ex.Message);
}
return;
}
private static void RunTest(bool causeArgumentException, bool
causeOutOfMemoryException)
{
// the number of test pages to put into the list
int numTestPages = 150;
List<Image> list = new List<Image>();
// get n unique single-page image objects loaded into our
collection
for (int i = 1; i <= numTestPages; i++) {
Debug.WriteLine("Adding page " + i.ToString());
if (causeArgumentException) {
// this exception takes a few loops before it will happen
list.Add(new Bitmap(1728, 2244));
}
else {
// this doesn't cause an exception
list.Add(new Bitmap(1728, 2244,
PixelFormat.Format1bppIndexed));
}
}
// iterate over every page in the list and replace it with a
copy,
// disposing of the old pages as we go
for (int i = 0; i < list.Count; i++) {
// the memory used by the program does not increase
substantially as the program runs
Debug.WriteLine(string.Format("Page {0}, Memory used: {1}", i
+ 1, System.GC.GetTotalMemory(true)));
// get a pointer to the old page
Image oldpage = list[i];
if (causeOutOfMemoryException) {
// this is the line that eventually causes the crash
Bitmap newpage = new Bitmap(oldpage);
// remove the old page from the collection
list.RemoveAt(i);
// insert the new page in the old page's place
list.Insert(i, newpage);
// dispose the old page
oldpage.Dispose();
}
}
}
}
}
Date:Mon, 13 Aug 2007 11:11:41 -0700
Author:
|
Re: ArgumentException and OutOfMemoryException in Bitmap constructor
1728*2244*4=15,510,528 bytes per image. This is the case for a 32 bits per
pixel image and is reasonably accurate because 1728 is divisible by four so
the padding is the same. How many times does the loop run? 15.5 megs per
image will pretty soon fill up the memory.
The 1bpp format however uses 1728/8*2244 which yields 484704 bytes for the
image buffer and a few bytes for the palette. You can get roughly 16 times
more 1bpp images in the same memory.
--
--
Bob Powell [MVP]
Visual C#, System.Drawing
Ramuseco Limited .NET consulting
http://www.ramuseco.com
Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm
Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm
All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.
"vector" wrote in message
news:1187028701.594048.207260@g4g2000hsf.googlegroups.com...
> I'm trying to write a program that spins through a List collection of
> Image objects and manipulates them. Unfortunately I keep encountering
> exceptions where I don't understand why they're happening. I've
> stripped down my app into a sample program that has the same flaws in
> it.
>
> The first exception happens in a loop where I create and add Bitmap
> objects to a List. The message is "Parameter is not valid," and it
> can be avoided by adding "PixelFormat.Format1bppIndexed" to the Bitmap
> constructor.
>
> The second exception is an out of memory error, where I'm trying in a
> loop to create a deep copy of each Image object in the List,
> manipulate it (but not in the sample code below), and replace the old
> Image in the List with the new Image.
>
> I really don't understand what's going wrong here. Can someone please
> explain this to me?
>
> using System;
> using System.Drawing;
> using System.Drawing.Imaging;
> using System.IO;
> using System.Diagnostics;
> using System.Collections.Generic;
>
> namespace ConsoleApplication2
> {
> class Program
> {
> [STAThread]
> static void Main(string[] args)
> {
> try {
> bool causeArgumentException = false;
> bool causeOutOfMemoryException = true;
> RunTest(causeArgumentException, causeOutOfMemoryException);
> }
> catch (ArgumentException ex) {
> //A first chance exception of type 'System.ArgumentException'
> occurred in System.Drawing.dll
> // at System.Drawing.Bitmap..ctor(Int32 width, Int32 height,
> PixelFormat format)
> // at System.Drawing.Bitmap..ctor(Int32 width, Int32 height)
> // at ConsoleApplication2.Program.RunTest(Boolean
> causeOutOfMemoryException) in c:\source\ImagePro2008\ImagePro
> \Class1.cs:line 49
> // at ConsoleApplication2.Program.Main(String[] args) in c:
> \source\ImagePro2008\ImagePro\Class1.cs:line 17
> Debug.WriteLine(ex.StackTrace);
>
> // Parameter is not valid.
> Debug.WriteLine(ex.Message);
> }
> catch (OutOfMemoryException ex) {
> // A first chance exception of type
> 'System.OutOfMemoryException' occurred in System.Drawing.dll
> // at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
> // at System.Drawing.Graphics.DrawImage(Image image, Int32 x,
> Int32 y, Int32 width, Int32 height)
> // at System.Drawing.Bitmap..ctor(Image original, Int32 width,
> Int32 height)
> // at System.Drawing.Bitmap..ctor(Image original)
> // at ConsoleApplication2.Program.RunTest(Boolean
> causeOutOfMemoryException)
> // at ConsoleApplication2.Program.Main(String[] args)
> Debug.WriteLine(ex.StackTrace);
>
> // Out of memory.
> Debug.WriteLine(ex.Message);
> }
>
> return;
> }
>
> private static void RunTest(bool causeArgumentException, bool
> causeOutOfMemoryException)
> {
> // the number of test pages to put into the list
> int numTestPages = 150;
>
> List<Image> list = new List<Image>();
>
> // get n unique single-page image objects loaded into our
> collection
> for (int i = 1; i <= numTestPages; i++) {
> Debug.WriteLine("Adding page " + i.ToString());
>
> if (causeArgumentException) {
> // this exception takes a few loops before it will happen
> list.Add(new Bitmap(1728, 2244));
> }
> else {
> // this doesn't cause an exception
> list.Add(new Bitmap(1728, 2244,
> PixelFormat.Format1bppIndexed));
> }
> }
>
> // iterate over every page in the list and replace it with a
> copy,
> // disposing of the old pages as we go
> for (int i = 0; i < list.Count; i++) {
> // the memory used by the program does not increase
> substantially as the program runs
> Debug.WriteLine(string.Format("Page {0}, Memory used: {1}", i
> + 1, System.GC.GetTotalMemory(true)));
>
> // get a pointer to the old page
> Image oldpage = list[i];
>
> if (causeOutOfMemoryException) {
> // this is the line that eventually causes the crash
> Bitmap newpage = new Bitmap(oldpage);
>
> // remove the old page from the collection
> list.RemoveAt(i);
>
> // insert the new page in the old page's place
> list.Insert(i, newpage);
>
> // dispose the old page
> oldpage.Dispose();
> }
> }
> }
> }
> }
>
Date:Mon, 13 Aug 2007 21:26:13 +0200
Author:
|
Re: ArgumentException and OutOfMemoryException in Bitmap constructor
On Aug 13, 3:26 pm, "Bob Powell [MVP]"
wrote:
> 1728*2244*4=15,510,528 bytes per image. This is the case for a 32 bits per
> pixel image and is reasonably accurate because 1728 is divisible by four so
> the padding is the same. How many times does the loop run? 15.5 megs per
> image will pretty soon fill up the memory.
Both loops run 150 times, the value of numTestPages.
> The 1bpp format however uses 1728/8*2244 which yields 484704 bytes for the
> image buffer and a few bytes for the palette. You can get roughly 16 times
> more 1bpp images in the same memory.
I think you've misunderstood the problem. The first loop -- the one
that populates the List with Bitmap objects -- throws an
ArgumentException, not an OutOfMemoryException, when I don't specify
the PixelFormat. Why would an ArgumentException be thrown if the
problem is that the images are too large?
The second loop -- the one that replaces the Image objects in the List
with new Bitmaps -- is the one that throws an OutOfMemoryException,
only I don't understand why. The original Image objects should be
Disposed and garbage collected as the loop runs, taking up no more
memory than they did originally. That is, if I populated the list in
the first loop, that should be enough proof that the second loop has
all the space it needs. Using a List of 150 1bpp images, here's a
snippet of the debug output from that failure, which seems to say I
still have plenty of memory to use. Maybe System.GC.GetTotalMemory
doesn't report what I think it does?
....
Page 119, Memory used: 374068
Page 120, Memory used: 374068
Page 121, Memory used: 374068
A first chance exception of type 'System.OutOfMemoryException'
occurred in System.Drawing.dll
at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
at System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y,
Int32 width, Int32 height)
at System.Drawing.Bitmap..ctor(Image original, Int32 width, Int32
height)
at System.Drawing.Bitmap..ctor(Image original)
at ConsoleApplication2.Program.RunTest(Boolean
causeArgumentException, Boolean causeOutOfMemoryException) in c:\source
\ImagePro2008\ImagePro\Class1.cs:line 80
at ConsoleApplication2.Program.Main(String[] args) in c:\source
\ImagePro2008\ImagePro\Class1.cs:line 18
Out of memory.
Date:Mon, 13 Aug 2007 13:23:08 -0700
Author:
|
Re: ArgumentException and OutOfMemoryException in Bitmap constructor
> Why would an ArgumentException be thrown if the
> problem is that the images are too large?
I don't know the answer to that, but I'm quite sure that is your problem. A
32 bit managed program is limited to ~2GB virtual memory and will typically
start being prone to running out of memory when it reaches ~1.5GB especially
when you are asking for large contiguous blocks. You only need to use simple
arithmetic to determine that what you are attempting is impossible in a 32
bit environment.
Cheers
Doug Forster
Date:Tue, 14 Aug 2007 08:59:13 +1200
Author:
|
|
|