Re: garbage collection and NSConnection
Re: garbage collection and NSConnection
- Subject: Re: garbage collection and NSConnection
- From: Marcel Weiher <email@hidden>
- Date: Fri, 11 Jul 2008 00:21:02 -0700
There are several ways to share the implementation:
1. Do nothing, CF and Foundation already do it for most of their
objects
(and they share their implementation...probably
unreasonably...)
This, obviously, doesn't work for your own classes.
But a lot of the objects you will use will tend to be Foundation
objects, especially if you've adopted the temp-object-heavy style.
2. Implement a common superclass
This doesn't work if you're subclassing something other than
NSObject already.
Non-NSObject subclasses tend to be things like NSViews which are
fairly heavy-weight and not that temporary.
3. Implement a function, inline function or macro that takes a
pointer
to the refcount ivar.
This works, but still leaves you to copy/paste glue code everywhere.
You don't even have to do that if you don't want to.
Not every solution works in every context, but combined, they cover
the bases rather well, making sharing the implementation quite easy.
In my experience.
[not referring to scanning overhead]
- Temporary objects get a 'release' at the end of their life, and
usually an 'autorelease' at the beginning.
The cost of a single refcounting op is negligible compared to the cost
of object allocation, so these two are quite irrelevant.
- Jumping objects across the end of an autorelease pool by retaining
them before destroying the pool.
In my experience, this is rather rare, and the cost once again tends
to be completely negligible compared to the cost of destroying the
pool and the objects in the pool.
- Paranoid or thread-safe accessors do a retain/autorelease dance
before returning.
This one is actually a problem. Don't do that, it isn't actually
thread-safe and can cause at least as many problems as it 'solves'.
Yes, just like objects don't get retained when they are stored in
local
variables, that happens when you store them into instance variables.
They do get released though, which is a refcount operation that
doesn't happen in the GC world.
Once again, the -release is completely negligible compared to the
actual deallocation.
Taking into account the programming style a language supports is
about as
far from a micro-optimization as you can get. It is an architectural
concern that informs how you structure your system, changing it
after-the-fact often turns out to be impossible. At least that's
been my
experience over the last 20 years or so, YMMV.
I'm not sure I understand what you're saying here. My point is that
ObjC makes it very easy and natural to create temporary objects
without worrying about their lifetimes.
That is exactly my point: this is one case where the comparative ease
is deceptive, as creating lots of temporary objects is not something
that Objective-C supports well. Objective-C is a *hybrid* OO
language, not a pure OO language.
In my experience, code which goes to great lengths to avoid
autoreleased objects is messy and much
more bug prone than the "normal" way.
Yes, if it is autoreleasing you avoid, not object creation in the
first place. The extra autorelease only costs you maybe 30%, the
extra object allocation costs you an order of magnitude or more. So
for example, my standard pattern for initialization is something like
this:
-init {
self=[super init];
[self setFoo:[Bar bar]];
return self;
}
Thus, yes, you can avoid many
autoreleased objects if you want, but this is a painful micro
optimization, not the standard way to do things.
Once again, avoiding temporary object-creation is not a micro-
optimization, and creating lots of temporary objects is definitely NOT
the standard way to do things in Objective-C.
You might have heard about the 80/20 rule, which is actually more a
90/10 or
95/05 rule: most of the execution time is spent in a very small
portion of
your code. Being able to go in and *really* optimize those hotspots
actually gives you the most bang for the buck. The "typical
usage", meaning
the bulk of the program, generally does not matter.
I did my master's thesis on high performance code and optimization; I
am more than vaguely familiar with these concepts.
Glad to hear that! However, in the sections above you were
continually treating ops that differ in cost by an order of magnitude
or more with equal weight, which makes me somewhat dubious of your
claimed credentials...
My point is merely that GC can help you without you needing to
change your code in any
way. This, to me, is more valuable than peppering my code with lots of
painful manual memory management to make it go faster.
...as does this. Once again: this is not about randomly "peppering"
code with "lots of painful manual memory management", this is about
(a) adopting a coding style that is clean, (b) flows with what
Objective-C provides and is good at and (c) allows for the highly
focused optimizations that actually make an impact, rather than
wasting it on the parts of the code that don't matter.
This is one of those areas where Objective-C really, really
excels: the
ability to combine very high-level, very abstracted code with small
bits of
highly optimized code to get an optimum balance of expressiveness and
performance.
I agree, but I don't agree with your proposed methods.
I haven't seen any indication that you know what my proposed methods
are. They certainly do not involve peppering code with micro-
optimizations or
I've optimized lots of ObjC code in my time, and I've never found it
necessary or
even particularly helpful to perform these refcounting or allocation
tricks you discuss. In my experience, object allocation and
refcounting are never hotspots.
I've given some references to back up my claim...the Postscript
interpreter I wrote in Objective-C is 20x faster because of object-
caching, turning it from laughably slow to competitive with the
industry standard. MPWXmlKit is around 10x faster than other XML
scanners, again due in large part to object caching.
Your experience may differ. In fact, I know that it *does* differ,
because we've had that conversation before. But, to be perfectly
frank, your experience is not going to change my mind.
"I have my opinion, who cares about facts or evidence"
...as does doing the work during the top of the event loop when the
machine
is waiting for user input.
This doesn't work when you're compute bound, which is of course the
only time that performance actually matters anyway.
The latter part is only true iff your apps do not need to responsive.
This is absolutely not true.
It is.
If your computation is impacting responsiveness, then you are
compute bound
for that constraint, pure and simple.
This is true, but it doesn't make your above statement true.
Also let's remember the context here. I said that running the GC on a
background thread means that it comes "for free", and you said that
doing work at the top of the event loop is also "for free".
Exactly.
It's obviously *not* for free if there is another pending event
waiting to
be processed.
Just like stuff on the background is not free if it ties up bus
bandwidth (which it does, it is scanning after all), or you could have
used the CPU for other means or you are counting power. In two of
those cases, doing the work at the end of the event loop is actually
better than doing it concurrently. And let's remember that once you
are compute-bound, you get much more bang-for-the-buck from targeting
the 5% hot-spot than from off-loading extra work to another thread.
In other words, doing a bunch of memory management work
in the event loop is much more likely to impact responsiveness than
doing GC work on a background thread.
That's a strong assertion. Care to back it up with some evidence? My
guess is that the opposite is the case: once the user has her
response from the system, the wait-time to the next user event will
typically be much greater.
Finally, please recall that I never said that GC is better for
everything or that it will provide more performance in all cases.
Please recall that I never said anything here about the qualities of
GC or RC in general. I just corrected some "minor" factual errors.
I only said that GC is not necessarily slower, and that which one is
faster depends greatly on exactly what your application is doing and
how it's written.
Exactly. In Objective-C, a temp-object-heavy style will almost
invariably make your application significantly slower, unless what it
is doing is sufficiently light-weight that it simply doesn't matter.
With the problem there being that when your users start filling your
app with data, what you thought initially would be sufficient will
turn out not to be.
Marcel
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden