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 (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