Accessing buffers in NSData/NSMutableData under garbage collection
Accessing buffers in NSData/NSMutableData under garbage collection
- Subject: Accessing buffers in NSData/NSMutableData under garbage collection
- From: Rick Hoge <email@hidden>
- Date: Mon, 18 Feb 2008 17:21:14 -0500
I have a question about recommended coding style under GC, which I'll
preface with some background.
I've been trying to learn about garbage collection under Leopard by
turning it on in some older apps and watching how they fail. As
stated in the GC docs, you probably don't want to switch to GC in a
mature application that was developed under the older memory
management scheme. However studying the effects of GC in old apps
was certainly helpful in planning better design patterns for future
projects.
One of the patterns that breaks badly is the following type of thing:
float *myPointer = [[NSMutableData dataWithLength:size*sizeof(float)]
mutableBytes];
This was convenient as a lazy (if perhaps misguided) way to replace
malloc with something that I knew I could use until the end of the
current event loop, and which would then be freed automatically. Note
that aside from the lazy, autoreleased malloc replacement, there are
many other cases where I use NSMutableDatas (e.g. where the data will
be used as an instance variable for one or more objects)
It's quite possible that this was a bad thing to do under the old
style of memory management, but it's fatal under GC. As far as the
collector is concerned, the inner NSMutableData object is no longer
reachable at later points during execution (whatever that means after
compiler optimization). If you use myPointer later, it's quite likely
that it will point to freed memory. Using
__strong float *myPointer = [[NSMutableData
dataWithLength:size*sizeof(float)] mutableBytes];
does not seem to be a solution, since (at least as I understand it)
the collector cares about references specifically to the NSMutableData
object and a strong pointer to an internal storage buffer (not an
object) won't prevent the object and its associated bytes from being
reclaimed (since the buffer can not "reach" the object).
Ok, fine. I can live with that. Now, however, I need to decide how
to replace the following kind of thing:
////////////////////////////////////////////////////////////////////// Start
code snippet //////////////////////////////////////////
NSMutableData *myData = [NSMutableData
dataWithLength:size*sizeof(float)];
float *myPointer = [myData mutableBytes]; // Don't think __strong
would make a difference here
int ix;
for (ix=0; ix<size; ix++) myPointer[ix] = mysillyfunction(ix); // This
causes an intermittent crash
// Insert Thousands of lines of code here
BOOL someFlag = YES;
if (someFlag) {
// Collector will probably have nuked myData a long time ago...
usually crashes by here
float answer = myPointer[3];
}
////////////////////////////////////////////////////////////////////// End
code snippet //////////////////////////////////////////
So this leads to the following questions:
- am I correct in understanding that it is a bad idea to *ever* copy
the pointer returned by -mutableBytes (or any other pointer-returning
method) to a variable for future use, since this assignment can't be
followed by the collector, which might at any time reclaim the parent
object? (use of __strong not withstanding?)
- so is the preferred if not mandatory alternative to *always* use the
-mutableBytes method in any line of code that needs to access the data
of an NSMutableData object? I can do this, but it seems to make the
code less readable (not the end of the world - clearly it's better
than crashing).
- should I expect a significant performance cost to the overhead of
the method call inside of a tight loop? e.g. for
(ix=0:ix<size;ix++) *((float*)[myData mutableBytes] + ix) =
somefunc(ix*3.0);
vs.
(ix=0:ix<size;ix++) myPointer[ix] = somefunc(ix*3.0);
- would I have been better to just use __strong *float myPointer =
NSAllocateCollectible(size*sizeof(float),0)? My instinct (under pre-
GC) has been to use NSData or NSMutableData for memory buffers that
might end up being assigned as instance variables to other objects.
Under the GC world, what are the advantages of NSData/NSMutableData
vs. a buffer returned by NSAllocateCollectible()? I have encountered
situations where NSMutableData is unable to allocate very large memory
buffers (e.g. 700MB) when GC is turned on (the same line of code is
works with GC off). NSAllocateCollectible() does not seem hindered by
these limitations for large blocks of memory under GC.
Thanks in advance for any suggestions,
Rick
_______________________________________________
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