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 (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]

Reply via email to