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:
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.
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".
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 -