Re: Garbage collector vs variable lifetime
Re: Garbage collector vs variable lifetime
- Subject: Re: Garbage collector vs variable lifetime
- From: Quincey Morris <email@hidden>
- Date: Sat, 7 Jun 2008 01:32:21 -0700
I'm fairly satisfied with Bill's (and others') suggested workarounds
about how to keep the object from being collected, but if I might
ramble just a little:
On Jun 6, 2008, at 22:03, Bill Bumgarner wrote:
On Jun 6, 2008, at 9:16 PM, Ken Thomases wrote:
And... we're back to retain/release.
The issue is, how can one know when this technique is necessary?
The supposed rules of GC are, if it's in a stack variable, it's
safe. The compiler here is doing something behind the programmer's
back, which the programmer can't really predict, that's changing
the rules.
I agree that the important part is that "the programmer can't really
predict". You have to scrutinize the source to see the places where
the compiler *might* optimize a variable lifetime. And remember to do
it.
Quoting the Garbage Collection Programming Guide: "The initial root
set of objects is comprised of global variables, stack variables,
and objects with external references. These objects are never
considered as garbage"
Given my understanding of the words involved here, this quoted
statement is nonsensical if taken literally. Objects (in the sense of
memory blocks known to the GC) are not the same as variables. There
are no variables in the initial root set of objects, only objects.
Presumably, what is meant is "objects whose pointers are currently
held in global variables and stack variables". I also never understood
what "objects with external references" meant. Are they objects with
external references *to* them from somewhere else? That sounds like
global variables again. Or objects with references to other objects?
Why would that in itself put the referring objects in the initial root
set, and why would those references need to be called "external"?
Further, AFAIK, the reference to "stack variables" just isn't true. If
I understand the clues in posts made here over the past months, it's
got nothing to do with variables. The GC simply (AFAIK) scans all
"live" areas of the stack for pointer-sized values that look like GC-
managed object pointers, and adds those objects to the initial root
set. (Ditto for registers, I assume, though I don't recall that being
mentioned.) The compiler (AFAIK) doesn't emit any code or information
to identify object pointer variable addresses, or to manage object
lifetimes (except for object references via pointers held in instance
variables, but that's a different matter). If you put a numerical
value into an int stack variable that happens to be the bit pattern of
some GC object address, it will (AFAIK) count as a root reference that
will keep the object from being collected.
For some values of "never".
Objective-C 2.0's garbage collection system is incompatible with
any optimization which changes which variables are on the stack.
More accurately, it's an error if compiler optimizations change
what are considered root objects.
I wouldn't say "which variables are on the stack", but rather "which
stack variables are live at any given point in the source code". For
example, at the end of the method's (outermost) scope, all its stack
variables are no longer live.
Clearly, it's incorrect for a compiler optimization to cause a change
of the value at a stack address used by a live variable, but that's
not happening here.
So it's more a question of whether it's an error for a compiler
optimization to change the lifetime of a variable. Bill's answer is,
"No, because the lifetime of a variable is by definition whatever the
compiler chooses to make it after optimizing."
(And, of course, the lifetime of a variable is something entirely
different from the lifetime of an object.)
The problem here is that there is no way for the compiler to know
that the char* bytes is somehow connected to the lifespan of the
NSData*. Nor is there any way for the collector to know that the
char* bytes is somehow an implied root of the NSData* object.
The compiler isn't changing roots and it isn't doing anything that
is a bug -- it is merely optimizing the code to use the resources
available by recycling bits of memory that refer to items that,
given all knowledge that it has, are no longer needed.
There is actually no guarantee that the -bytes method will return a
reference to a malloc'd block of data; it may return an arbitrary
pointer into some other Data's hunk of data.
This is an edge case. It is uncommon and the kind of edge case
that only exists when you dip below Objective-C and into the realm
of C.
It seems to me that the consequence of working around this issue is
that every scope in which a NSData* variable is declared must be
carefully examined for variable lifetime issues (or a '[data self]'-
style sentinel routinely placed at the end of every such scope). EVERY
scope. Given the central role that NSData plays in Cocoa file I/O and
Core Data (to name a couple of really obvious examples), it doesn't
sound so edgy. What's actually uncommon is the chance of getting
zapped by an unluckily-timed garbage collection. (In my app, the loop
where this happened had over 1.6 million iterations, so that upped the
chance quite a bit.)
As usual, I've gone on too long. Sorry about that.
_______________________________________________
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