473,395 Members | 1,681 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

How expensive is brush creation?

I am doing quite a bit of custom painting and it means I have to
create a lot of brushes (think one for every file system object in a
directory) per paint. How expensive is this? Should I find a way to
create the brushes once, store them in an member variable, and use
them when I need them? Or is creating brushes a throw-away process
that doesn't take a lot of work?

Thanks for the info.

Tom P.
Aug 5 '08 #1
31 3364
On Tue, 05 Aug 2008 10:54:38 -0700, Tom P. <pa***********@gmail.comwrote:
I am doing quite a bit of custom painting and it means I have to
create a lot of brushes (think one for every file system object in a
directory) per paint. How expensive is this? Should I find a way to
create the brushes once, store them in an member variable, and use
them when I need them? Or is creating brushes a throw-away process
that doesn't take a lot of work?
What's the speed difference when you measure your two proposed
implementations? What performance problem are you trying to solve?

If the answers to those questions are "I haven't measured" and/or "no
particular performance problem", then you are premature in worrying about
the expense of creating a brush.

Pete
Aug 5 '08 #2
On 5 août, 19:54, "Tom P." <padilla.he...@gmail.comwrote:
I am doing quite a bit of custom painting and it means I have to
create a lot of brushes (think one for every file system object in a
directory) per paint. How expensive is this? Should I find a way to
create the brushes once, store them in an member variable, and use
them when I need them? Or is creating brushes a throw-away process
that doesn't take a lot of work?

Thanks for the info.

Tom P.
It is VERY expensive, not because of the brushes themselves, but
because you're feeding the Garbage Collector with all those brushes on
every Paint event.

You'd be better off using the system Brushes, which are static. Use:

Brushes.Black

instead of:

Brush b = new SolidBrush(Color.Black)

If you frequently use the same colors that are outside the 216
predefined ones, you can do this (in a static class, for instance):

private static Brush orangeyBrush;

public static Brush Orangey
{
get
{
if (orangeyBrush == null)
return (orangeyBrush = new
SolidBrush(Color.FromArgb(223,156,0)));
}
}

This mimics what the framework does internally (lazy initialization).

Michel
Aug 5 '08 #3
On 5 août, 20:01, "Peter Duniho" <NpOeStPe...@nnowslpianmk.comwrote:
On Tue, 05 Aug 2008 10:54:38 -0700, Tom P. <padilla.he...@gmail.comwrote:
I am doing quite a bit of custom painting and it means I have to
create a lot of brushes (think one for every file system object in a
directory) per paint. How expensive is this? Should I find a way to
create the brushes once, store them in an member variable, and use
them when I need them? Or is creating brushes a throw-away process
that doesn't take a lot of work?

What's the speed difference when you measure your two proposed *
implementations? *What performance problem are you trying to solve?

If the answers to those questions are "I haven't measured" and/or "no *
particular performance problem", then you are premature in worrying about*
the expense of creating a brush.

Pete
Yes, I assumed "paint" meant "paint event". If it is "paint" as in
"image" or "picturebox" for instance, Pete's right, the improvement
might hamper readability for a negligible gain.

Michel
Aug 5 '08 #4
On Aug 5, 1:54 pm, "Tom P." <padilla.he...@gmail.comwrote:
I am doing quite a bit of custom painting and it means I have to
create a lot of brushes (think one for every file system object in a
directory) per paint. How expensive is this? Should I find a way to
create the brushes once, store them in an member variable, and use
them when I need them? Or is creating brushes a throw-away process
that doesn't take a lot of work?

Thanks for the info.

Tom P.
Hi,

I do not know for sure in managed world but in unmanaged a Brush is a
system ersource, so you have to be careful with it.
Why you need that many?
Aug 5 '08 #5
On Aug 5, 1:01*pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Tue, 05 Aug 2008 10:54:38 -0700, Tom P. <padilla.he...@gmail.comwrote:
I am doing quite a bit of custom painting and it means I have to
create a lot of brushes (think one for every file system object in a
directory) per paint. How expensive is this? Should I find a way to
create the brushes once, store them in an member variable, and use
them when I need them? Or is creating brushes a throw-away process
that doesn't take a lot of work?

What's the speed difference when you measure your two proposed *
implementations? *What performance problem are you trying to solve?

If the answers to those questions are "I haven't measured" and/or "no *
particular performance problem", then you are premature in worrying about*
the expense of creating a brush.

Pete
Nothing I've measured but the effort of redesigning my framework to
accommodate static brushes is no small feat. I am writing a file
manager and I custom paint each listview subitem (using
OnDrawSubItem). I allow custom colors and lineargradient brushes for
each subitem (name, size, and date). I have taken count and I'm
creating over 1000 brushes just to pull up a directory listing of the
root of my dev PC. Now I'm thinking about adding a color option for
Directories vs. Files (and maybe even readonly etc.) and so I'm forced
to wonder if the painting could get expensive.

Tom P.
Aug 5 '08 #6
On Aug 5, 1:12*pm, michel.desang...@gmail.com wrote:
On 5 août, 19:54, "Tom P." <padilla.he...@gmail.comwrote:
I am doing quite a bit of custom painting and it means I have to
create a lot of brushes (think one for every file system object in a
directory) per paint. How expensive is this? Should I find a way to
create the brushes once, store them in an member variable, and use
them when I need them? Or is creating brushes a throw-away process
that doesn't take a lot of work?
Thanks for the info.
Tom P.

It is VERY expensive, not because of the brushes themselves, but
because you're feeding the Garbage Collector with all those brushes on
every Paint event.

You'd be better off using the system Brushes, which are static. Use:

Brushes.Black

instead of:

Brush b = new SolidBrush(Color.Black)

If you frequently use the same colors that are outside the 216
predefined ones, you can do this (in a static class, for instance):

private static Brush orangeyBrush;

public static Brush Orangey
{
* get
* {
* * if (orangeyBrush == null)
* * * *return (orangeyBrush = new
SolidBrush(Color.FromArgb(223,156,0)));
* *}

}

This mimics what the framework does internally (lazy initialization).

Michel

I appreciate the help but I've got custom colors and lineargradient
brushes just littering this thing. As well as mouseover brushes and
now I'm kicking around the idea of Directory vs. File brushes and
maybe System or ReadOnly brushes. I've got to find a way to make them
permanent but I've also got the issue of creating the brush within the
correct bounds (what if the user changes the size of the column, I
need to resize the brush accordingly).

I'm gonna have to think this one through. Thanks.

Tom P.
Aug 5 '08 #7
On Tue, 05 Aug 2008 11:12:01 -0700, <mi**************@gmail.comwrote:
It is VERY expensive, not because of the brushes themselves, but
because you're feeding the Garbage Collector with all those brushes on
every Paint event.
The GC design is optimized to handle repeated allocation and discarding of
short-lived objects. GC is not an issue here at all, though disposal of
brushes _theoretically_ might be. I doubt most code would see any issue.
You'd be better off using the system Brushes, which are static. Use:

Brushes.Black
Yes, very true. If one of the pre-defined brushes is adequate, using that
is much better than creating and disposing one.

Pete
Aug 5 '08 #8
On Aug 5, 1:22*pm, "Ignacio Machin ( .NET/ C# MVP )"
<ignacio.mac...@gmail.comwrote:
On Aug 5, 1:54 pm, "Tom P." <padilla.he...@gmail.comwrote:
I am doing quite a bit of custom painting and it means I have to
create a lot of brushes (think one for every file system object in a
directory) per paint. How expensive is this? Should I find a way to
create the brushes once, store them in an member variable, and use
them when I need them? Or is creating brushes a throw-away process
that doesn't take a lot of work?
Thanks for the info.
Tom P.

Hi,

I do not know for sure in managed world but in unmanaged a Brush is a
system ersource, so you have to be careful with it.
Why you need that many?
You bring up a very good point: what the heck am I doing? I made the
incorrect assumption that this would be a "yes/No" question and I'd be
done with it. My apologies all around.

I am making a file manager that paints each item in custom colors and
gradients at custom angles (lineargradient brushes). The mouseover
event will repaint the item with a custom mouseover brush. With each
subitem getting it's own paint event (OnDrawSubItem) this results in
~1,000 brushes for a simple 10 directory root drive.

Now I'm contemplating the addition of Directory Vs. File brushes and
even System vs. ReadOnly brushes. Hence the question.

Tom P.
Aug 5 '08 #9
On Tue, 05 Aug 2008 11:23:04 -0700, Tom P. <pa***********@gmail.comwrote:
[...]
>What's the speed difference when you measure your two proposed Â*
implementations? Â*What performance problem are you trying to solve?
[...]

Nothing I've measured but the effort of redesigning my framework to
accommodate static brushes is no small feat.
All the more reason to not do that unless you know for sure you have to.
I am writing a file
manager and I custom paint each listview subitem (using
OnDrawSubItem). I allow custom colors and lineargradient brushes for
each subitem (name, size, and date). I have taken count and I'm
creating over 1000 brushes just to pull up a directory listing of the
root of my dev PC.
1000 brushes? To display just one directory?

All due respect, I doubt the human brain is capable of comprehending a UI
presentation with that much variety in it.
Now I'm thinking about adding a color option for
Directories vs. Files (and maybe even readonly etc.) and so I'm forced
to wonder if the painting could get expensive.
Well, it _could_. Especially if just one directory causes you to create
1000 different brushes. But as long as things are performing adequately,
I don't think you should worry about it. Even if you do run into
performance issues, you might reconsider whether it's really necessary to
use so many different brushes. That is probably a better solution than
trying to cache thousands of brushes (as Ignacio points out, the unmanaged
resource in a brush is relatively scarce and so shouldn't be held on to
for long periods of time, especially in such large numbers).

Pete
Aug 5 '08 #10
On Aug 5, 1:41*pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Tue, 05 Aug 2008 11:23:04 -0700, Tom P. <padilla.he...@gmail.comwrote:
[...]
What's the speed difference when you measure your two proposed *
implementations? *What performance problem are you trying to solve?
[...]
Nothing I've measured but the effort of redesigning my framework to
accommodate static brushes is no small feat.

All the more reason to not do that unless you know for sure you have to.
I am writing a file
manager and I custom paint each listview subitem (using
OnDrawSubItem). I allow custom colors and lineargradient brushes for
each subitem (name, size, and date). I have taken count and I'm
creating over 1000 brushes just to pull up a directory listing of the
root of my dev PC.

1000 brushes? *To display just one directory?

All due respect, I doubt the human brain is capable of comprehending a UI*
presentation with that much variety in it.
Now I'm thinking about adding a color option for
Directories vs. Files (and maybe even readonly etc.) and so I'm forced
to wonder if the painting could get expensive.

Well, it _could_. *Especially if just one directory causes you to create *
1000 different brushes. *But as long as things are performing adequately, *
I don't think you should worry about it. *Even if you do run into *
performance issues, you might reconsider whether it's really necessary to*
use so many different brushes. *That is probably a better solution than*
trying to cache thousands of brushes (as Ignacio points out, the unmanaged *
resource in a brush is relatively scarce and so shouldn't be held on to *
for long periods of time, especially in such large numbers).

Pete
I'm sorry, I must have misspoke. I don't create a thousand different
brushes, I only create about 6 or 9 different brushes... hundreds of
times. Each Item has a NameBrush, a SizeBrush, and a DateBrush for
each circumstance they could be in (unselected, selected, mouseover,
etc.). But they are created over and over and over again for each item
in the filelist. For example, everytime I pass the mouse pointer over
an item I must create three of the unselected brushes to "clear" the
old items look, then I must create three new brushes to paint the new
items mouseover look. That's 6 brushes just to move the mouse from one
item to the next.

Tom P.
Aug 5 '08 #11
On Tue, 05 Aug 2008 11:27:45 -0700, Tom P. <pa***********@gmail.comwrote:
I appreciate the help but I've got custom colors and lineargradient
brushes just littering this thing. As well as mouseover brushes and
now I'm kicking around the idea of Directory vs. File brushes and
maybe System or ReadOnly brushes. I've got to find a way to make them
permanent but I've also got the issue of creating the brush within the
correct bounds (what if the user changes the size of the column, I
need to resize the brush accordingly).
One possible "in-between" solution you might consider is to keep just one
static brush instance, updated as necessary. Maintain some sort of
description of the brush so you know what's actually in that brush (which
you'd have to do with any static brush caching anyway).

If an item has multiple elements, each that might be drawn with its own
brush, you could increase the number of static brushes to the maximum
number of brushes any one element might use.

That way, if several items with the same visual appearance are drawn in
immediate succession, you can just use the brush(es) from the last drawing
operation rather than recreating the brushes anew each time. At the same
time, it avoids you having to implement a full-fledged brush caching
system (the code for which would be much more complicated, never mind the
system resource cost of keeping thousands of brushes or more around
full-time).

Pete
Aug 5 '08 #12
On 5 août, 20:27, "Peter Duniho" <NpOeStPe...@nnowslpianmk.comwrote:
On Tue, 05 Aug 2008 11:12:01 -0700, <michel.desang...@gmail.comwrote:
It is VERY expensive, not because of the brushes themselves, but
because you're feeding the Garbage Collector with all those brushes on
every Paint event.

The GC design is optimized to handle repeated allocation and discarding of *
short-lived objects. *GC is not an issue here at all, though disposal of *
brushes _theoretically_ might be. *I doubt most code would see any issue.
You'd be better off using the system Brushes, which are static. Use:
Brushes.Black

Yes, very true. *If one of the pre-defined brushes is adequate, using that *
is much better than creating and disposing one.

Pete
Still, this :
for (int i = 0; i < 1000000; i++)
{
Brush b = new SolidBrush(Color.Blue);
}
...in release mode takes something like 160 Mb of RAM and lasts
approximately one second. Even optimized, it has to put some pressure
on the GC. But again, when reading Tom's description I incorrectly
assumed "lots" meant "millions of brushes" (I'm working on a rather
complex real-time video thingy atm where every cycle saved is
crucial). You're absolutely right it amounts to nothing in Tom's case.

Michel
Aug 5 '08 #13
On Aug 5, 2:27 pm, "Tom P." <padilla.he...@gmail.comwrote:
On Aug 5, 1:12 pm, michel.desang...@gmail.com wrote:
On 5 août, 19:54, "Tom P." <padilla.he...@gmail.comwrote:
I am doing quite a bit of custom painting and it means I have to
create a lot of brushes (think one for every file system object in a
directory) per paint. How expensive is this? Should I find a way to
create the brushes once, store them in an member variable, and use
them when I need them? Or is creating brushes a throw-away process
that doesn't take a lot of work?
Thanks for the info.
Tom P.
It is VERY expensive, not because of the brushes themselves, but
because you're feeding the Garbage Collector with all those brushes on
every Paint event.
You'd be better off using the system Brushes, which are static. Use:
Brushes.Black
instead of:
Brush b = new SolidBrush(Color.Black)
If you frequently use the same colors that are outside the 216
predefined ones, you can do this (in a static class, for instance):
private static Brush orangeyBrush;
public static Brush Orangey
{
get
{
if (orangeyBrush == null)
return (orangeyBrush = new
SolidBrush(Color.FromArgb(223,156,0)));
}
}
This mimics what the framework does internally (lazy initialization).
Michel

I appreciate the help but I've got custom colors and lineargradient
brushes just littering this thing. As well as mouseover brushes and
now I'm kicking around the idea of Directory vs. File brushes and
maybe System or ReadOnly brushes. I've got to find a way to make them
permanent but I've also got the issue of creating the brush within the
correct bounds (what if the user changes the size of the column, I
need to resize the brush accordingly).

I'm gonna have to think this one through. Thanks.

Tom P.

Ok, that's fine
but why you need to create XXXXX number of DIFFERENT brushes? I would
assume that you need one per type at most.
Aug 5 '08 #14
On Tue, 05 Aug 2008 11:56:24 -0700, Ignacio Machin ( .NET/ C# MVP )
<ig************@gmail.comwrote:
but why you need to create XXXXX number of DIFFERENT brushes? I would
assume that you need one per type at most.
I assume it's because he's doing the drawing in a handler that gets called
once per item, so each item has no knowledge of other items that got drawn.

If one was doing the whole UI at once in a single Paint handler, it would
be easy to batch up all the brushes (or even to sort the drawing by brush,
which would be the best performance). But if he draws 1000 items, and is
creating and disposing the brushes in the item-drawing handler (which is
not fundamentally a bad design at all), then that's 1000 different brushes.

I didn't pick up on that initially, but based on his other replies, that
seems like what's going on.

Pete
Aug 5 '08 #15
On Tue, 05 Aug 2008 11:51:19 -0700, <mi**************@gmail.comwrote:
Still, this :
for (int i = 0; i < 1000000; i++)
{
Brush b = new SolidBrush(Color.Blue);
}
...in release mode takes something like 160 Mb of RAM and lasts
approximately one second.
Well, that's only about 170 bytes per object. Doesn't sound like a big
deal to me. But, what happens when you fix the code so that it is
correctly disposing each brush? At least some of the memory cost is
coming from the unmanaged resource being allocated. And more importantly,
do you have any evidence at all that the GC itself is spending a lot of
time working on dealing with the allocations?
Even optimized, it has to put some pressure
on the GC. But again, when reading Tom's description I incorrectly
assumed "lots" meant "millions of brushes" (I'm working on a rather
complex real-time video thingy atm where every cycle saved is
crucial). You're absolutely right it amounts to nothing in Tom's case.
Even a million short-lived objects shouldn't really be a big deal. Even
if you allocate 100,000 objects in quick succession, each allocation
involves just a single update of a pointer, just as it always does.
Assuming the objects are no longer reachable the next time garbage
collection happens, there's no significant overhead to the collection
process caused by those objects.

If anything, keeping the objects cached statically could increase GC
overhead, because that adds to the number of objects the GC needs to
examine as it traverses the graph of reachable objects.

The real issue here is the unmanaged resources, not the garbage collection.

Pete
Aug 5 '08 #16
On Tue, 05 Aug 2008 11:49:44 -0700, Tom P. <pa***********@gmail.comwrote:
I'm sorry, I must have misspoke. I don't create a thousand different
brushes, I only create about 6 or 9 different brushes... hundreds of
times. [...]
Right, I finally figured that out. :) I might just not have been reading
carefully enough the first time.

I don't think that caching a dozen or so brushes long-term should be an
issue, if you decide that's a viable design change. That's not enough to
cause any serious problems with resource consumption, I think.

Still, I wouldn't bother until if and when you find an actual performance
problem. Just remember to dispose any brushes you create, and you'll
probably be fine.

Pete
Aug 5 '08 #17
On Aug 5, 2:09*pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Tue, 05 Aug 2008 11:49:44 -0700, Tom P. <padilla.he...@gmail.comwrote:
I'm sorry, I must have misspoke. I don't create a thousand different
brushes, I only create about 6 or 9 different brushes... hundreds of
times. [...]

Right, I finally figured that out. *:) *I might just not have been reading *
carefully enough the first time.

I don't think that caching a dozen or so brushes long-term should be an *
issue, if you decide that's a viable design change. *That's not enough to *
cause any serious problems with resource consumption, I think.

Still, I wouldn't bother until if and when you find an actual performance*
problem. *Just remember to dispose any brushes you create, and you'll *
probably be fine.

Pete
Thanks for the help guys. Pete is right, I should have done this
sooner but I was stuck thinking about something from one direction.
Thanks to Michel for giving me the kick in the head to realize how
simple a short test could be.

Using the following code...

for (long loop = 0; loop 1000000000;loop++ )
{
Rectangle tempRect = new Rectangle(0,0,100, 18);

tempBrush = new LinearGradientBrush(tempRect,
Color.Blue, Color.Red, 0.01F) ;
tempBrush = null;
}

...takes 0.00013344 secs. (timed using the hardware HiRes API timer).

I think I can spare 0.00013344 secs.

Sorry Pete.

Tom P.
Aug 5 '08 #18
On 5 août, 21:06, "Peter Duniho" <NpOeStPe...@nnowslpianmk.comwrote:
On Tue, 05 Aug 2008 11:51:19 -0700, <michel.desang...@gmail.comwrote:
Still, this :
for (int i = 0; i < 1000000; i++)
{
* *Brush b = new SolidBrush(Color.Blue);
}
...in release mode takes something like 160 Mb of RAM and lasts
approximately one second.

Well, that's only about 170 bytes per object. *Doesn't sound like a big*
deal to me. *But, what happens when you fix the code so that it is *
correctly disposing each brush? *At least some of the memory cost is *
coming from the unmanaged resource being allocated. *And more importantly, *
do you have any evidence at all that the GC itself is spending a lot of *
time working on dealing with the allocations?
Even optimized, it has to put some pressure
on the GC. But again, when reading Tom's description I incorrectly
assumed "lots" meant "millions of brushes" (I'm working on a rather
complex real-time video thingy atm where every cycle saved is
crucial). You're absolutely right it amounts to nothing in Tom's case.

Even a million short-lived objects shouldn't really be a big deal. *Even *
if you allocate 100,000 objects in quick succession, each allocation *
involves just a single update of a pointer, just as it always does. *
Assuming the objects are no longer reachable the next time garbage *
collection happens, there's no significant overhead to the collection *
process caused by those objects.

If anything, keeping the objects cached statically could increase GC *
overhead, because that adds to the number of objects the GC needs to *
examine as it traverses the graph of reachable objects.

The real issue here is the unmanaged resources, not the garbage collection.

Pete
The only evidence I have is "Effective C#" by Bill Wagner, in which
chapter 16, "Minimize Garbage", deals with the handling of brushes in
paint handlers. It's a coincidence, I read it yesterday, so I thought
I'd jump in. Extracts :

"No matter how you look at it, allocating and destroying a heap-based
object takes more processor time than not allocating and not
destroying a heap-based object. [...] One very common bad practice is
to allocate GDI objects in a Windows Paint handler [...] The static
property Brushes.Black illustrates another technique that you should
use to avoid repeatedly allocating similar objects. Create static
member variables for commonly used instances of the reference types
you need. [...] Every time you need to draw something in your window
using the color Black, you need a black brush. you create and destroy
a huge number of black brushes during the course of a program. [...]
The garbage collector does an efficient job of managing the memory
that your application uses. But remember that creating and destroying
heap objects still takes time. Avoid creating excessive objects; don't
create what you don't need. Also avoid creating multiple objects of
reference types in local functions. Instead, consider promoting local
variables to member variables, or create static objects of the most
common instances of your types."

The first sentence seems to apply quite nicely here.

Oh, and Brush and SolidBrush both implement IDisposable and inherit
from MarshalByRef. So, let me disagree completely with you on that GC
matter...

Michel
Aug 5 '08 #19
On Tue, 05 Aug 2008 12:39:59 -0700, <mi**************@gmail.comwrote:
The only evidence I have is "Effective C#" by Bill Wagner, in which
chapter 16, "Minimize Garbage", deals with the handling of brushes in
paint handlers.
Well, I don't know anything about that book. But you should be careful
about believing everything you read, as well as about what you apply it to.

It's trivially true (and thus uninteresting) that it's faster to not do
something than to do it. But that doesn't mean that the act of doing it
is a significant cost that warrants complicating the code just so you can
avoid doing it.
[...]
Oh, and Brush and SolidBrush both implement IDisposable and inherit
from MarshalByRef. So, let me disagree completely with you on that GC
matter...
I have no idea what you mean. Even if I hadn't specifically pointed out
that the object needs to be disposed (which I in fact did), what's that
got to do with whether or not the memory management overhead is
significant? What's your point?

Pete
Aug 5 '08 #20
On 5 août, 21:17, "Tom P." <padilla.he...@gmail.comwrote:
On Aug 5, 2:09*pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:


On Tue, 05 Aug 2008 11:49:44 -0700, Tom P. <padilla.he...@gmail.comwrote:
I'm sorry, I must have misspoke. I don't create a thousand different
brushes, I only create about 6 or 9 different brushes... hundreds of
times. [...]
Right, I finally figured that out. *:) *I might just not have been reading *
carefully enough the first time.
I don't think that caching a dozen or so brushes long-term should be an*
issue, if you decide that's a viable design change. *That's not enough to *
cause any serious problems with resource consumption, I think.
Still, I wouldn't bother until if and when you find an actual performance *
problem. *Just remember to dispose any brushes you create, and you'll*
probably be fine.
Pete

Thanks for the help guys. Pete is right, I should have done this
sooner but I was stuck thinking about something from one direction.
Thanks to Michel for giving me the kick in the head to realize how
simple a short test could be.

Using the following code...

for (long loop = 0; loop 1000000000;loop++ )
* * * * * * {
* * * * * * * * Rectangle tempRect = new Rectangle(0,0,100, 18);

* * * * * * * * tempBrush = new LinearGradientBrush(tempRect,
Color.Blue, Color.Red, 0.01F) ;
* * * * * * * * tempBrush = null;
* * * * * * }

...takes 0.00013344 secs. (timed using the hardware HiRes API timer).

I think I can spare 0.00013344 secs.

Sorry Pete.

Tom P.- Masquer le texte des messages précédents -

- Afficher le texte des messages précédents -
Er... Did you copy/paste from Visual Studio ? Because if you did,
maybe you should try again, changing the ">" into a "<"... and remove
three zeros in your loop, otherwise you'll still be waiting
tomorrow... Prepare to be surprised !

Michel
Aug 5 '08 #21
On 5 août, 21:53, "Peter Duniho" <NpOeStPe...@nnowslpianmk.comwrote:
On Tue, 05 Aug 2008 12:39:59 -0700, <michel.desang...@gmail.comwrote:
The only evidence I have is "Effective C#" by Bill Wagner, in which
chapter 16, "Minimize Garbage", deals with the handling of brushes in
paint handlers.

Well, I don't know anything about that book. *But you should be careful*
about believing everything you read, as well as about what you apply it to.
Maybe you should read it before advising anything, or assuming it's
some sort of "dummies book"? Also, exactly what makes you think I'm
the credulous type, or have less experience than you have, or am less
cautious in the way I acquire new information?
It's trivially true (and thus uninteresting) that it's faster to not do *
something than to do it. *But that doesn't mean that the act of doing it *
is a significant cost that warrants complicating the code just so you can*
avoid doing it.
I was speaking about this particular case, not in general. The time
saved should be significant enough to warrant *simplifying* the code.
[...]
Oh, and Brush and SolidBrush both implement IDisposable and inherit
from MarshalByRef. So, let me disagree completely with you on that GC
matter...

I have no idea what you mean. *Even if I hadn't specifically pointed out *
that the object needs to be disposed (which I in fact did), what's that *
got to do with whether or not the memory management overhead is *
significant? *What's your point?
This is a reference type (harder on the GC than value types), which
implements IDisposable (two method calls, including
GCSuppressFinalize), and marshalls its data accross boundaries (which
is, sorry to be trivial, longer than not marshalling data accross
boundaries).

In the end, exactly what's your problem with me saying that allocating
unnecessary objects is unnecessary and, in this case, expensive? Could
you explain in simple terms? Did it rub you the wrong way?

Michel
Aug 5 '08 #22
On Tue, 05 Aug 2008 13:09:30 -0700, <mi**************@gmail.comwrote:
Maybe you should read it before advising anything, or assuming it's
some sort of "dummies book"? Also, exactly what makes you think I'm
the credulous type, or have less experience than you have, or am less
cautious in the way I acquire new information?
What makes you think I think any of that?

I'm simply pointing out that the quote you included doesn't change
anything I wrote.
>It's trivially true (and thus uninteresting) that it's faster to not do
Â*
something than to do it. Â*But that doesn't mean that the act of doing
it Â*
is a significant cost that warrants complicating the code just so you
can Â*
avoid doing it.

I was speaking about this particular case, not in general. The time
saved should be significant enough to warrant *simplifying* the code.
Why? What makes you think it "should be significant enough"? Did you
measure it in the real-world context?

If you have specific facts, please share them. If you don't, then you
have no basis for arguing in favor of complicating the design. And yes,
it's a complication to change from simply allocating objects as needed to
caching them over time. I don't see any justification for your claim that
the change could be described as "*simplifying* the code".
[...]
Oh, and Brush and SolidBrush both implement IDisposable and inherit
from MarshalByRef. So, let me disagree completely with you on that GC
matter...

I have no idea what you mean. Â*Even if I hadn't specifically pointed
out Â*
that the object needs to be disposed (which I in fact did), what's that
Â*
got to do with whether or not the memory management overhead is Â*
significant? Â*What's your point?

This is a reference type (harder on the GC than value types),
Huh? Value types aren't managed by the GC at all. That parenthetical
statement makes no sense at all. At the very most, it's trivially true
(and so again, uninteresting).
which
implements IDisposable (two method calls, including
GCSuppressFinalize), and marshalls its data accross boundaries (which
is, sorry to be trivial, longer than not marshalling data accross
boundaries).
So what? None of that increases the _garbage collector's_ workload. The
object itself has more overhead, yes. But that wasn't the point.
In the end, exactly what's your problem with me saying that allocating
unnecessary objects is unnecessary and, in this case, expensive? Could
you explain in simple terms? Did it rub you the wrong way?
You are the one who seems to be rubbed the wrong way. I am simply
pointing out that there's no evidence at all that Tom's original "allocate
as needed" design is in need of changing (other than using the pre-defined
brushes where possible, which I already agree with you about).

If he's measured the cost and found his application is spending too much
time drawing these items, then yes...there's some value in exploring other
designs that don't allocate these objects over and over again. But a)
even if he found some performance cost that needed fixing, it's
_extremely_ unlikely that it would be related to the GC (i.e. you'd find
the same cost just creating GDI brushes in unmanaged code), and b) so far
there's been no demonstration of such a performance cost in need of fixing.

Pete
Aug 5 '08 #23
On 5 août, 22:20, "Peter Duniho" <NpOeStPe...@nnowslpianmk.comwrote:
On Tue, 05 Aug 2008 13:09:30 -0700, <michel.desang...@gmail.comwrote:
Maybe you should read it before advising anything, or assuming it's
some sort of "dummies book"? Also, exactly what makes you think I'm
the credulous type, or have less experience than you have, or am less
cautious in the way I acquire new information?

What makes you think I think any of that?
The sentence you snipped : "you should be careful about believing
everything you read, as well as about what you apply it to".
I'm simply pointing out that the quote you included doesn't change *
anything I wrote.
It's trivially true (and thus uninteresting) that it's faster to not do *
*
something than to do it. *But that doesn't mean that the act of doing *
it *
is a significant cost that warrants complicating the code just so you *
can *
avoid doing it.
I was speaking about this particular case, not in general. The time
saved should be significant enough to warrant *simplifying* the code.

Why? *What makes you think it "should be significant enough"? *Did you *
measure it in the real-world context?
Yep, see the loop example above.
If you have specific facts, please share them. *If you don't, then you *
have no basis for arguing in favor of complicating the design. *And yes, *
it's a complication to change from simply allocating objects as needed to*
caching them over time. *I don't see any justification for your claim that *
the change could be described as "*simplifying* the code".
I don't see any justification for your claim that declaring a static
member variable is more complicated than allocating several instance
ones.
[...]
Oh, and Brush and SolidBrush both implement IDisposable and inherit
from MarshalByRef. So, let me disagree completely with you on that GC
matter...
I have no idea what you mean. *Even if I hadn't specifically pointed*
out *
that the object needs to be disposed (which I in fact did), what's that *
*
got to do with whether or not the memory management overhead is *
significant? *What's your point?
This is a reference type (harder on the GC than value types),

Huh? *Value types aren't managed by the GC at all. *That parenthetical *
statement makes no sense at all. *At the very most, it's trivially true*
(and so again, uninteresting).
Lol ! So it's nonsensical BUT trivially true. Reminds me of this :
http://thedailywtf.com/Articles/What...uth_0x3f_.aspx
which
implements IDisposable (two method calls, including
GCSuppressFinalize), and marshalls its data accross boundaries (which
is, sorry to be trivial, longer than not marshalling data accross
boundaries).

So what? *None of that increases the _garbage collector's_ workload. *The *
object itself has more overhead, yes. *But that wasn't the point.
Er... I didn't say those two points increased the GC workload, *you*
assumed I did (reread the sentence); I was talking about the
allocation/deallocation overhead, and THAT was the point of the OP.
In the end, exactly what's your problem with me saying that allocating
unnecessary objects is unnecessary and, in this case, expensive? Could
you explain in simple terms? Did it rub you the wrong way?

You are the one who seems to be rubbed the wrong way. *I am simply *
pointing out that there's no evidence at all that Tom's original "allocate *
as needed" design is in need of changing (other than using the pre-defined *
brushes where possible, which I already agree with you about).
Argumentum ad ignorantiam : http://en.wikipedia.org/wiki/Argument_from_ignorance

You do a lot of those !
If he's measured the cost and found his application is spending too much *
time drawing these items, then yes...there's some value in exploring other *
designs that don't allocate these objects over and over again. *But a) *
even if he found some performance cost that needed fixing, it's *
_extremely_ unlikely that it would be related to the GC (i.e. you'd find *
the same cost just creating GDI brushes in unmanaged code), and b) so far*
there's been no demonstration of such a performance cost in need of fixing.
a) Some random writer, apparently a professionnal programmer, seems to
strongly disagree with you, and has even written a chapter about that
in his book; and I should add that "unlikely that it would be related
to the GC" is pretty silly (the GC workload is directly related to the
number of objects created/destroyed, AND DON'T PICK ON THAT ONE, I
mean objects as in reference types), and b) yes there is, try my loop,
and his loop once you correct the typo.

In short, you're trying to establish that he shouldn't try to improve
his program, based on several assumptions on your part : he's using
only a few brushes, the program won't run for long, the paint event
won't be called often, etc.

So, again : yes, Tom, you should go the extra mile to make your
brushes static for a lot of reasons : your code will be clearer,
faster, will use less memory, will spend less time in the GC, and you
will learn good habits in the process.

And, Pete, people who say "All the more reason to not do that unless
you know for sure you have to" shouldn't be giving tips to people who
write, create, invent or try to discover or improve. Programmers ?

Michel
Aug 5 '08 #24
On Aug 5, 2:57*pm, michel.desang...@gmail.com wrote:
On 5 août, 21:17, "Tom P." <padilla.he...@gmail.comwrote:
On Aug 5, 2:09*pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Tue, 05 Aug 2008 11:49:44 -0700, Tom P. <padilla.he...@gmail.comwrote:
I'm sorry, I must have misspoke. I don't create a thousand different
brushes, I only create about 6 or 9 different brushes... hundreds of
times. [...]
Right, I finally figured that out. *:) *I might just not have been reading *
carefully enough the first time.
I don't think that caching a dozen or so brushes long-term should be an *
issue, if you decide that's a viable design change. *That's not enough to *
cause any serious problems with resource consumption, I think.
Still, I wouldn't bother until if and when you find an actual performance *
problem. *Just remember to dispose any brushes you create, and you'll *
probably be fine.
Pete
Thanks for the help guys. Pete is right, I should have done this
sooner but I was stuck thinking about something from one direction.
Thanks to Michel for giving me the kick in the head to realize how
simple a short test could be.
Using the following code...
for (long loop = 0; loop 1000000000;loop++ )
* * * * * * {
* * * * * * * * Rectangle tempRect = new Rectangle(0,0,100, 18);
* * * * * * * * tempBrush = new LinearGradientBrush(tempRect,
Color.Blue, Color.Red, 0.01F) ;
* * * * * * * * tempBrush = null;
* * * * * * }
...takes 0.00013344 secs. (timed using the hardware HiRes API timer).
I think I can spare 0.00013344 secs.
Sorry Pete.
Tom P.- Masquer le texte des messages précédents -
- Afficher le texte des messages précédents -

Er... Did you copy/paste from Visual Studio ? Because if you did,
maybe you should try again, changing the ">" into a "<"... and remove
three zeros in your loop, otherwise you'll still be waiting
tomorrow... Prepare to be surprised !

Michel
Nope, taken right out of the VS-IDE and pasted in here. If you want
the entire code I suppose I could paste it here as well.

the HiRes timer uses...
[DllImport("kernel32.dll")]
internal extern static UInt32 QueryPerformanceCounter(ref Int64
lpPerformanceCount);

... to get the timings.

Tom P.
Aug 5 '08 #25
On Tue, 05 Aug 2008 13:52:42 -0700, <mi**************@gmail.comwrote:
On 5 août, 22:20, "Peter Duniho" <NpOeStPe...@nnowslpianmk.comwrote:
>On Tue, 05 Aug 2008 13:09:30 -0700, <michel.desang...@gmail.comwrote:
Maybe you should read it before advising anything, or assuming it's
some sort of "dummies book"? Also, exactly what makes you think I'm
the credulous type, or have less experience than you have, or am less
cautious in the way I acquire new information?

What makes you think I think any of that?

The sentence you snipped : "you should be careful about believing
everything you read, as well as about what you apply it to".
Do you disagree with the sentence? If not, I don't see what your problem
is. The quote you provided is nothing as compared to a real-world test.
[...]
I was speaking about this particular case, not in general. The time
saved should be significant enough to warrant *simplifying* the code.

Why? Â*What makes you think it "should be significant enough"? Â*Did you Â*
measure it in the real-world context?

Yep, see the loop example above.
The loop in which you forgot to dispose the brush you allocated, forcing
the GC to have to do finalization on them (eventually)? And yet in which
you still were able to create 1,000,000 in a second? At 1000 brushes per
frame (per Tom's comments), that's 1000 frames per second, about ten times
faster than any typical computer display can handle. Even if Tom upped
his brush count to 10,000 Brush instances per frame, he could still draw
100 frames in a second. That's plenty fast for a 1st-person-shooter,
never mind an application displaying information about a file system.

And of course, all that assumes that brush creation accounts for the vast
majority of time spent drawing, which is unlikely. So in practice it's
even more absurd to worry about the performance of the Brush
creation/destruction than demonstrated by your own analysis.

Again, where's the performance problem here?
[...]
I don't see any justification for your claim that declaring a static
member variable is more complicated than allocating several instance
ones.
I never suggesting "allocating [sic]" instance variables. My impression
of Tom's design is that he's allocating brushes in a method, storing them
in a local variable just long enough for that method to execute. My
suggestion was that there's nothing fundamentally wrong with that design.
The only reference to "static" I made was in the context of an object that
remains allocated (i.e. "statically") rather than being recreated with
each use (i.e. "dynamically").

My use of the word has nothing to do with static or instance members of
classes. A long-term cache of brushes could in fact be implemented either
way (i.e. stored in static or instance members), but that's not what I'm
talking about at all.
[...]
This is a reference type (harder on the GC than value types),

Huh? Â*Value types aren't managed by the GC at all. Â*That parenthetical Â*
statement makes no sense at all. Â*At the very most, it's trivially true
Â*
(and so again, uninteresting).

Lol ! So it's nonsensical BUT trivially true.
"At the very most", it's trivially true. In practice, since the GC
doesn't manage value types at all, it's nonsensical to compare the
difficulty of the GC in managing reference types versus value types.

I'm sorry you don't comprehend the subtleties in my statement. But the
fact remains, it doesn't make sense to discuss how "hard" management of
value types is on the garbage collector. The GC just doesn't manage them
at all.

Yes, in a sense that means it's no work at all for the GC. But only in
the same sense that it's no work at all for you to mow my lawn. Do you
really think it makes sense to talk about how much harder it is for you to
mow your own lawn than mine, given that you don't do the latter at all?
[...]
>So what? Â*None of that increases the _garbage collector's_ workload.
The Â*
object itself has more overhead, yes. Â*But that wasn't the point.

Er... I didn't say those two points increased the GC workload, *you*
assumed I did (reread the sentence); I was talking about the
allocation/deallocation overhead, and THAT was the point of the OP.
This whole sub-thread started here:

On Tue, 05 Aug 2008 11:27:00 -0700, Peter Duniho
<Np*********@nnowslpianmk.comwrote:
On Tue, 05 Aug 2008 11:12:01 -0700, <mi**************@gmail.comwrote:
>It is VERY expensive, not because of the brushes themselves, but
because you're feeding the Garbage Collector with all those brushes on
every Paint event.

The GC design is optimized to handle repeated allocation and discarding
of short-lived objects. GC is not an issue here at all, though disposal
of brushes _theoretically_ might be. I doubt most code would see any
issue.
As you can see, my only contribution here has always been about the GC
overhead. Nothing more. If you choose to infer a broader discussion,
that's your mistake. If you choose to inject comments irrelevant to the
original discussion, don't expect me to find them relevant.
>
In the end, exactly what's your problem with me saying that allocating
unnecessary objects is unnecessary and, in this case, expensive? Could
you explain in simple terms? Did it rub you the wrong way?

You are the one who seems to be rubbed the wrong way. Â*I am simply Â*
pointing out that there's no evidence at all that Tom's original
"allocate Â*
as needed" design is in need of changing (other than using the
pre-defined Â*
brushes where possible, which I already agree with you about).

Argumentum ad ignorantiam :
http://en.wikipedia.org/wiki/Argument_from_ignorance
Uh. You should probably read that Wikipedia article more closely. It has
nothing to do with this discussion. From a purely practical matter, it
makes no sense to optimize code until you know it's a piece of code in
need of optimizing. This is completely different from "argumentum ad
ignorantiam".
You do a lot of those !
Ad hominem will get you nowhere.
[...]
a) Some random writer, apparently a professionnal programmer, seems to
strongly disagree with you,
Well, technically I disagree with him. But whatever.
and has even written a chapter about that
in his book;
The fact that it's in print doesn't mean it's true, never mind applicable
to the implementation at hand.
and I should add that "unlikely that it would be related
to the GC" is pretty silly
I didn't write that. I wrote "_extremely_ unlikely...".
(the GC workload is directly related to the
number of objects created/destroyed, AND DON'T PICK ON THAT ONE,
Why not? It's patently false. The workload is not _directly_ related to
the number of objects created/destroyed. In fact, short-lived objects
incur a MUCH lower per-object cost to the GC than
long-lived-but-still-transient objects (that is, objects that age out of
generation 0).

There is not a direct correlation. There's an indirect relationship, but
no direct correlation.

More importantly, whether there's a direct correlation or not, it's the
actual _cost_ that's at issue here. And even if the cost was directly
proportional to the number of objects, the per-object cost is so tiny
relative to what else is going on in the code, the GC overhead is
"_extremely_ unlikely" to be significant.
I mean objects as in reference types), and b) yes there is, try my loop,
and his loop once you correct the typo.
Your loop still has a bug in it, but even so it fails to prove that the GC
cost is significant. It's much more likely that the cost of allocating
and disposing the _unmanaged_ resources overwhelms whatever insignificant
cost the GC incurs.

You can do the test yourself. Time these two loops and compare:

for (long i = 0; i < 1000000; i++)
{
object obj = new object();
}

and:

for (long i = 0; i < 1000000; i++)
{
using (Brush brush = new SolidBrush(Color.Blue))
{
}
}

On my computer, the second completes in about 1.1 seconds (similar to your
results). The first completes in about 0.02 seconds.

In other words, in a loop that is _only_ creating and destroying a Brush,
the GC-related activity incurs only 2% of the total cost of the loop.
That's before doing _anything_ else interesting in the loop.

No, it's pretty clear: when dealing with the Brush class, most of the cost
incurred managing the object has nothing to do with the GC. Inasmuch as
there's any expense at all, it's the object itself that is costly (and as
your own test shows, it's not even that costly, when you compare it to
what is considered a reasonable frame rate from the user's point of view).

I'm sorry you took such offense at my point of correction to your original
statement, and I'm especially sorry that it's taking so much effort to
explain myself. But facts are facts.
In short, you're trying to establish that he shouldn't try to improve
his program, based on several assumptions on your part : he's using
only a few brushes, the program won't run for long, the paint event
won't be called often, etc.
No. I _am_ establishing that he shouldn't bother _changing_ his program
until he has some specific indication that doing so would be an
_improvement_. And I've made none of the assumptions that you claim I
have (in fact, quite the opposite).

You are engaging in tautology, having assumed that the change would be an
improvement before you have actually proven it to be so.
So, again : yes, Tom, you should go the extra mile to make your
brushes static for a lot of reasons : your code will be clearer,
faster, will use less memory, will spend less time in the GC, and you
will learn good habits in the process.

And, Pete, people who say "All the more reason to not do that unless
you know for sure you have to" shouldn't be giving tips to people who
write, create, invent or try to discover or improve. Programmers ?
Believe that at your own peril. You're going to waste a lot of time
optimizing code and making it more complicated for no useful benefit.

Pete
Aug 5 '08 #26
On Tue, 05 Aug 2008 14:36:15 -0700, Tom P. <pa***********@gmail.comwrote:
[...]
Using the following code...
for (long loop = 0; loop 1000000000;loop++ )
[...]

Er... Did you copy/paste from Visual Studio ? Because if you did,
maybe you should try again, changing the ">" into a "<"... and remove
three zeros in your loop, otherwise you'll still be waiting
tomorrow.. Prepare to be surprised !

Michel

Nope, taken right out of the VS-IDE and pasted in here. If you want
the entire code I suppose I could paste it here as well.
Right. His point is that since that's exactly the code you used to test
performance, it's not a useful test. Your loop doesn't even execute one
iteration. It will exit as soon as the condition "loop 1000000000" is
false, which it is on the very first comparison.

That said, his own test does a fine job demonstrating just how pointless
it is to worry about the cost of creating and destroying Brush instances.
You can do a million per second. It's highly unlikely that you'd put
enough information up on the screen at once for the user to be affected by
how long it takes to create and destroy a Brush instance.

Pete
Aug 5 '08 #27
On 5 août, 23:36, "Tom P." <padilla.he...@gmail.comwrote:
On Aug 5, 2:57*pm, michel.desang...@gmail.com wrote:


On 5 août, 21:17, "Tom P." <padilla.he...@gmail.comwrote:
On Aug 5, 2:09*pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Tue, 05 Aug 2008 11:49:44 -0700, Tom P. <padilla.he...@gmail.comwrote:
I'm sorry, I must have misspoke. I don't create a thousand different
brushes, I only create about 6 or 9 different brushes... hundredsof
times. [...]
Right, I finally figured that out. *:) *I might just not have been reading *
carefully enough the first time.
I don't think that caching a dozen or so brushes long-term should be an *
issue, if you decide that's a viable design change. *That's not enough to *
cause any serious problems with resource consumption, I think.
Still, I wouldn't bother until if and when you find an actual performance *
problem. *Just remember to dispose any brushes you create, and you'll *
probably be fine.
Pete
Thanks for the help guys. Pete is right, I should have done this
sooner but I was stuck thinking about something from one direction.
Thanks to Michel for giving me the kick in the head to realize how
simple a short test could be.
Using the following code...
for (long loop = 0; loop 1000000000;loop++ )
* * * * * * {
* * * * * * * * Rectangle tempRect = new Rectangle(0,0,100, 18);
* * * * * * * * tempBrush = new LinearGradientBrush(tempRect,
Color.Blue, Color.Red, 0.01F) ;
* * * * * * * * tempBrush = null;
* * * * * * }
...takes 0.00013344 secs. (timed using the hardware HiRes API timer).
I think I can spare 0.00013344 secs.
Sorry Pete.
Tom P.- Masquer le texte des messages précédents -
- Afficher le texte des messages précédents -
Er... Did you copy/paste from Visual Studio ? Because if you did,
maybe you should try again, changing the ">" into a "<"... and remove
three zeros in your loop, otherwise you'll still be waiting
tomorrow... Prepare to be surprised !
Michel

Nope, taken right out of the VS-IDE and pasted in here. If you want
the entire code I suppose I could paste it here as well.

the HiRes timer uses...
[DllImport("kernel32.dll")]
internal extern static UInt32 QueryPerformanceCounter(ref Int64
lpPerformanceCount);

... to get the timings.

Tom P.- Masquer le texte des messages précédents -

- Afficher le texte des messages précédents -
Yes, I know, I'm trying to tell you that you did a typo in your
loop !! It executes only once ! Come on, allocating one billion
objects can't take a millisecond ! Change :

for (long loop = 0; loop 1000000000;loop++ )

to :

for (long loop = 0; loop < 1000000000;loop++ )

...and time again, you'll see what I mean. And maybe that'll change
your mind...

Michel
Aug 5 '08 #28
On 05/08/2008 in message
<26**********************************@p25g2000hsf. googlegroups.comTom P.
wrote:
>Nope, taken right out of the VS-IDE and pasted in here. If you want
the entire code I suppose I could paste it here as well.
I suspect Michel meant:
>for (long loop = 0; loop 1000000000;loop++ )
that won't loop for long :-)

--
Jeff Gaines Damerham Hampshire UK
"Why is it that when we talk to God we're said to be praying,
but when God talks to us we're schizophrenic?"
Aug 5 '08 #29
On Aug 5, 4:49*pm, michel.desang...@gmail.com wrote:
On 5 août, 23:36, "Tom P." <padilla.he...@gmail.comwrote:
On Aug 5, 2:57*pm, michel.desang...@gmail.com wrote:
On 5 août, 21:17, "Tom P." <padilla.he...@gmail.comwrote:
On Aug 5, 2:09*pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Tue, 05 Aug 2008 11:49:44 -0700, Tom P. <padilla.he...@gmail.comwrote:
I'm sorry, I must have misspoke. I don't create a thousand different
brushes, I only create about 6 or 9 different brushes... hundreds of
times. [...]
Right, I finally figured that out. *:) *I might just not havebeen reading *
carefully enough the first time.
I don't think that caching a dozen or so brushes long-term shouldbe an *
issue, if you decide that's a viable design change. *That's notenough to *
cause any serious problems with resource consumption, I think.
Still, I wouldn't bother until if and when you find an actual performance *
problem. *Just remember to dispose any brushes you create, and you'll *
probably be fine.
Pete
Thanks for the help guys. Pete is right, I should have done this
sooner but I was stuck thinking about something from one direction.
Thanks to Michel for giving me the kick in the head to realize how
simple a short test could be.
Using the following code...
for (long loop = 0; loop 1000000000;loop++ )
* * * * * * {
* * * * * * * * Rectangle tempRect = new Rectangle(0,0,100, 18);
* * * * * * * * tempBrush = new LinearGradientBrush(tempRect,
Color.Blue, Color.Red, 0.01F) ;
* * * * * * * * tempBrush = null;
* * * * * * }
...takes 0.00013344 secs. (timed using the hardware HiRes API timer).
I think I can spare 0.00013344 secs.
Sorry Pete.
Tom P.- Masquer le texte des messages précédents -
- Afficher le texte des messages précédents -
Er... Did you copy/paste from Visual Studio ? Because if you did,
maybe you should try again, changing the ">" into a "<"... and remove
three zeros in your loop, otherwise you'll still be waiting
tomorrow... Prepare to be surprised !
Michel
Nope, taken right out of the VS-IDE and pasted in here. If you want
the entire code I suppose I could paste it here as well.
the HiRes timer uses...
[DllImport("kernel32.dll")]
internal extern static UInt32 QueryPerformanceCounter(ref Int64
lpPerformanceCount);
... to get the timings.
Tom P.- Masquer le texte des messages précédents -
- Afficher le texte des messages précédents -

Yes, I know, I'm trying to tell you that you did a typo in your
loop !! It executes only once ! Come on, allocating one billion
objects can't take a millisecond ! Change :

for (long loop = 0; loop 1000000000;loop++ )

to :

for (long loop = 0; loop < 1000000000;loop++ )

...and time again, you'll see what I mean. And maybe that'll change
your mind...

Michel
Don't tell my PM, please.

THIS loop...
tempTimer.Start();
for (int loop = 0; loop < 1000000; loop++)
{
tempRectangle = new Rectangle(0, 0, 100, 18);
tempBrush = new LinearGradientBrush(tempRectangle,
Color.Blue, Color.Red, 0.01F);

tempBrush.Dispose();
}
tempTimer.Stop();

...takes about 5.5 sec.
A mere 1000 brushes takes about 0.005 sec.

Which brings me to another question... Which is best, object.Dispose()
or Object = null?

Object = null only takes 4.3 secs but I can never keep straight which
one calls the GC twice or under what circumstances. (I can't keep the
stupid "for" loop straight, what are the odds I get this right?)

Tom P.
Aug 6 '08 #30
On Tue, 05 Aug 2008 17:23:11 -0700, Tom P. <pa***********@gmail.comwrote:
[...]
Which brings me to another question... Which is best, object.Dispose()
or Object = null?
Setting a local variable to "null" is pretty much never the right approach
to memory management.

Also, calling Dispose() is not optional in any case. If the object
implements IDisposable, you really do need to call Dispose() on the object
when you're done with it (before you lose track of the reference,
obviously).

Pete
Aug 6 '08 #31
On 5 août, 23:44, "Peter Duniho" <NpOeStPe...@nnowslpianmk.comwrote:
On Tue, 05 Aug 2008 13:52:42 -0700, <michel.desang...@gmail.comwrote:
On 5 août, 22:20, "Peter Duniho" <NpOeStPe...@nnowslpianmk.comwrote:
On Tue, 05 Aug 2008 13:09:30 -0700, <michel.desang...@gmail.comwrote:
Maybe you should read it before advising anything, or assuming it's
some sort of "dummies book"? Also, exactly what makes you think I'm
the credulous type, or have less experience than you have, or am less
cautious in the way I acquire new information?
What makes you think I think any of that?
The sentence you snipped : "you should be careful about believing
everything you read, as well as about what you apply it to".

Do you disagree with the sentence? *If not, I don't see what your problem *
is. *The quote you provided is nothing as compared to a real-world test..
[...]
I was speaking about this particular case, not in general. The time
saved should be significant enough to warrant *simplifying* the code..
Why? *What makes you think it "should be significant enough"? *Didyou *
measure it in the real-world context?
Yep, see the loop example above.

The loop in which you forgot to dispose the brush you allocated, forcing *
the GC to have to do finalization on them (eventually)? *And yet in which *
you still were able to create 1,000,000 in a second? *At 1000 brushes per *
frame (per Tom's comments), that's 1000 frames per second, about ten times *
faster than any typical computer display can handle. *Even if Tom upped*
his brush count to 10,000 Brush instances per frame, he could still draw *
100 frames in a second. *That's plenty fast for a 1st-person-shooter, *
never mind an application displaying information about a file system.

And of course, all that assumes that brush creation accounts for the vast*
majority of time spent drawing, which is unlikely. *So in practice it's*
even more absurd to worry about the performance of the Brush *
creation/destruction than demonstrated by your own analysis.

Again, where's the performance problem here?
[...]
I don't see any justification for your claim that declaring a static
member variable is more complicated than allocating several instance
ones.

I never suggesting "allocating [sic]" instance variables. *My impression *
of Tom's design is that he's allocating brushes in a method, storing them*
in a local variable just long enough for that method to execute. *My *
suggestion was that there's nothing fundamentally wrong with that design.*
The only reference to "static" I made was in the context of an object that *
remains allocated (i.e. "statically") rather than being recreated with *
each use (i.e. "dynamically").

My use of the word has nothing to do with static or instance members of *
classes. *A long-term cache of brushes could in fact be implemented either *
way (i.e. stored in static or instance members), but that's not what I'm *
talking about at all.
[...]
This is a reference type (harder on the GC than value types),
Huh? *Value types aren't managed by the GC at all. *That parenthetical *
statement makes no sense at all. *At the very most, it's trivially true *
*
(and so again, uninteresting).
Lol ! So it's nonsensical BUT trivially true.

"At the very most", it's trivially true. *In practice, since the GC *
doesn't manage value types at all, it's nonsensical to compare the *
difficulty of the GC in managing reference types versus value types.

I'm sorry you don't comprehend the subtleties in my statement. *But the*
fact remains, it doesn't make sense to discuss how "hard" management of *
value types is on the garbage collector. *The GC just doesn't manage them *
at all.

Yes, in a sense that means it's no work at all for the GC. *But only in*
the same sense that it's no work at all for you to mow my lawn. *Do you*
really think it makes sense to talk about how much harder it is for you to *
mow your own lawn than mine, given that you don't do the latter at all?
[...]
So what? *None of that increases the _garbage collector's_ workload.*
The *
object itself has more overhead, yes. *But that wasn't the point.
Er... I didn't say those two points increased the GC workload, *you*
assumed I did (reread the sentence); I was talking about the
allocation/deallocation overhead, and THAT was the point of the OP.

This whole sub-thread started here:

On Tue, 05 Aug 2008 11:27:00 -0700, Peter Duniho *

<NpOeStPe...@nnowslpianmk.comwrote:
On Tue, 05 Aug 2008 11:12:01 -0700, <michel.desang...@gmail.comwrote:
It is VERY expensive, not because of the brushes themselves, but
because you're feeding the Garbage Collector with all those brushes on
every Paint event.
The GC design is optimized to handle repeated allocation and discarding*
of short-lived objects. *GC is not an issue here at all, though disposal *
of brushes _theoretically_ might be. *I doubt most code would see any*
issue.

As you can see, my only contribution here has always been about the GC *
overhead. *Nothing more. *If you choose to infer a broader discussion, *
that's your mistake. *If you choose to inject comments irrelevant to the *
original discussion, don't expect me to find them relevant.
In the end, exactly what's your problem with me saying that allocating
unnecessary objects is unnecessary and, in this case, expensive? Could
you explain in simple terms? Did it rub you the wrong way?
You are the one who seems to be rubbed the wrong way. *I am simply *
pointing out that there's no evidence at all that Tom's original *
"allocate *
as needed" design is in need of changing (other than using the *
pre-defined *
brushes where possible, which I already agree with you about).
Argumentum ad ignorantiam : *
http://en.wikipedia.org/wiki/Argument_from_ignorance

Uh. *You should probably read that Wikipedia article more closely. *It has *
nothing to do with this discussion. *From a purely practical matter, it*
makes no sense to optimize code until you know it's a piece of code in *
need of optimizing. *This is completely different from "argumentum ad *
ignorantiam".
You do a lot of those !

Ad hominem will get you nowhere.
[...]
a) Some random writer, apparently a professionnal programmer, seems to
strongly disagree with you,

Well, technically I disagree with him. *But whatever.
and has even written a chapter about that
in his book;

The fact that it's in print doesn't mean it's true, never mind applicable*
to the implementation at hand.
and I should add that "unlikely that it would be related
to the GC" is pretty silly

I didn't write that. *I wrote "_extremely_ unlikely...".
(the GC workload is directly related to the
number of objects created/destroyed, AND DON'T PICK ON THAT ONE,

Why not? *It's patently false. *The workload is not _directly_ related to *
the number of objects created/destroyed. *In fact, short-lived objects *
incur a MUCH lower per-object cost to the GC than *
long-lived-but-still-transient objects (that is, objects that age out of *
generation 0).

There is not a direct correlation. *There's an indirect relationship, but *
no direct correlation.

More importantly, whether there's a direct correlation or not, it's the *
actual _cost_ that's at issue here. *And even if the cost was directly *
proportional to the number of objects, the per-object cost is so tiny *
relative to what else is going on in the code, the GC overhead is *
"_extremely_ unlikely" to be significant.
I mean objects as in reference types), and b) yes there is, try my loop,
and his loop once you correct the typo.

Your loop still has a bug in it, but even so it fails to prove that the GC *
cost is significant. *It's much more likely that the cost of allocating*
and disposing the _unmanaged_ resources overwhelms whatever insignificant*
cost the GC incurs.

You can do the test yourself. *Time these two loops and compare:

* * * * * * *for (long i = 0; i < 1000000; i++)
* * * * * * *{
* * * * * * * * *object obj = new object();
* * * * * * *}

and:

* * * * * * *for (long i = 0; i < 1000000; i++)
* * * * * * *{
* * * * * * * * *using (Brush brush = new SolidBrush(Color.Blue))
* * * * * * * * *{
* * * * * * * * *}
* * * * * * *}

On my computer, the second completes in about 1.1 seconds (similar to your *
results). *The first completes in about 0.02 seconds.

In other words, in a loop that is _only_ creating and destroying a Brush,*
the GC-related activity incurs only 2% of the total cost of the loop. *
That's before doing _anything_ else interesting in the loop.

No, it's pretty clear: when dealing with the Brush class, most of the cost *
incurred managing the object has nothing to do with the GC. *Inasmuch as *
there's any expense at all, it's the object itself that is costly (and as*
your own test shows, it's not even that costly, when you compare it to *
what is considered a reasonable frame rate from the user's point of view)..

I'm sorry you took such offense at my point of correction to your original *
statement, and I'm especially sorry that it's taking so much effort to *
explain myself. *But facts are facts.
In short, you're trying to establish that he shouldn't try to improve
his program, based on several assumptions on your part : he's using
only a few brushes, the program won't run for long, the paint event
won't be called often, etc.

No. *I _am_ establishing that he shouldn't bother _changing_ his program *
until he has some specific indication that doing so would be an *
_improvement_. *And I've made none of the assumptions that you claim I *
have (in fact, quite the opposite).

You are engaging in tautology, having assumed that the change would be an*
improvement before you have actually proven it to be so.
So, again : yes, Tom, you should go the extra mile to make your
brushes static for a lot of reasons : your code will be

...

plus de détails »- Masquer le texte des messages précédents -

- Afficher le texte des messages précédents -
Well, let's agree to disagree completely on all matters : I maintain
that GC has a lot of work to do because the OP's NOT disposing of the
brushes, which was obvious from his first post, and which is confirmed
by his last. In this case, the Dispose method IS called by the GC, or
called by whatever and then fed to the GC, which for all purposes and
intents, is pretty much the same. You're just nitpicking on details
and in the end, you're trying to establish that taking up 0.1% or a
processor's horsepower ONLY for brushes management (when it's
completely unnecessary) is acceptable ? But then, why take 0.1% when
you can easily - and with a better design - take 0.0001% ?

You forgot the original question, and your whole argument is based on
"if it works, don't fix it". Well, we should have remained with just
fire and the wheel, which worked brilliantly. The rest is just
optimization and I suspect if you were to say anything, we wouldn't
have gone further.

I'm out, I have designs to improve and microseconds to save !

Michel

Aug 6 '08 #32

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Chris Lacey | last post by:
Hi, I'm currently writing a scheduling service which starts a number DotNet executables, each within a new AppDomain, every ten seconds. The guts of the code is as follows: // For each...
1
by: Rene | last post by:
I would like to get a reference to a Brush using the color name of the brush. For example, right now if I want a brush with a certain color, I would hard code something like Brushes.PeachPuff, this...
1
by: Serdar YILMAZ | last post by:
2
by: boxim | last post by:
having a moment, cant you just Brush br = new Brush(Color.Black);??? saying you cant cos it's an abstract class need to get to a brush from a color tia sam martin
5
by: Dennis | last post by:
When I instantiate a Brush resource such as a solidbrush, do I need to dispose the resource when I'm finished or will it automatically be disposed when the function/sub it's used in ends? Thank...
1
by: =?Utf-8?B?UEtsZW1t?= | last post by:
how to serialize a brush object with the XmlSerializer without knowing the brush type?
2
by: Johnny J. | last post by:
I've got an inherited control where I want the user to be able to specify a color property. Using that color, I'm drawing a line private m_UserDefinedColor as Color ..... Dim g as...
0
by: steve | last post by:
When drawing with a hatch brush with a statement such as myGraphics.FillPolygon(hatchBrush, polygon.vertices); the hatch brush is always oriented in the same direction. Is there a way of...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.