Re: garbage collection and NSConnection
Re: garbage collection and NSConnection
- Subject: Re: garbage collection and NSConnection
- From: "Michael Ash" <email@hidden>
- Date: Thu, 10 Jul 2008 23:29:56 -0400
On Thu, Jul 10, 2008 at 7:33 PM, Marcel Weiher <email@hidden> wrote:
>
> On Jul 10, 2008, at 9:50 , Michael Ash wrote:
>
>> On Thu, Jul 10, 2008 at 12:17 PM, Marcel Weiher <email@hidden>
>> wrote:
>>>
>>> [hash tables not generally used + internal refcounts]
>
>> Atomic updates are still a pretty big hit on a multiprocessor system
>> (all of them, these days),
>
> Yes, they're definitely not free.
>
>> and implementing your own is a fair amount
>> of work that you simply don't have to do in a GC environment.
>
> Not really, no.
>
>> Especially since you can't reasonably implement it once and share the
>> implementation, you'll have to manually insert the implementation into
>> your classes individually.
>
> 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.
> 2. Implement a common superclass
This doesn't work if you're subclassing something other than NSObject already.
> 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.
>>>> They're pretty fast, but
>>>> there's certainly some cost there. Garbage collection lets you
>>>> eliminate all of this code, so you get a speed bonus there.
>>>
>>> GC does not eliminate this overhead, it replaces it with the overhead of
>>> the
>>> write-barrier functions that are called when you do an assignment. These
>>> calls are generated automatically by the compiler, so you don't see them
>>> in
>>> your code, but they are still function calls. This is in addition to the
>>> scanning overhead.
>>
>> It's not a replacement, because the overheads are not
>> identical, neither in time nor in location.
>
> Why do you say that? The write barrier code gets called when when you store
> an object into an instance variable, same as for a retain. They are
> actually at pretty much precisely the same time and location.
>
> I am guessing you are referring to the scanning overhead, about which you
> are right: it happens at a different time and in a different place, and in
> addition to the checks.
I'm not referring to the scanning overhead. There are many scenarios
where a refcount modification is made which do not produce a write
barrier in GC-land. For example:
- Temporary objects get a 'release' at the end of their life, and
usually an 'autorelease' at the beginning.
- Paranoid or thread-safe accessors do a retain/autorelease dance
before returning.
- Jumping objects across the end of an autorelease pool by retaining
them before destroying the pool.
>> For example, in the very
>> common scenario of creating temporary objects which never leave the
>> stack, a write barrier is never generated.
>
> 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.
>>> Also: don't gratuitously create and/or autorelease objects if you don't
>>> have to. Objective-C object-creation is pretty heavy-weight compared to
>>> other OO languages, regardless of wether you are using garbage collection
>>> or
>>> reference counting, so programming-styles that do a lot of
>>> object-creation
>>> will suffer, performance-wise.
>>
>> You can bend your programming style to micro-optimize the language's
>> speed if you want, but that's not the kind of thing I prefer to do.
>
> 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. In my experience, code which
goes to great lengths to avoid autoreleased objects is messy and much
more bug prone than the "normal" way. 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.
>> I'd rather look at how GC compares to refcounting in typical usage,
>> not this kind of carefully optimized usage that rarely happens.
>
> 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. 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.
> 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'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.
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.
>>> ...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. If your computation is impacting
responsiveness, then you are compute bound for that constraint, pure
and simple.
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". It's
obviously *not* for free if there is another pending event waiting to
be processed. 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.
Finally, please recall that I never said that GC is better for
everything or that it will provide more performance in all cases. 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.
Mike
_______________________________________________
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