I'm trying to keep track of my sprites in an array, add and remove
them from layers, and then finally clear them out of the array.
I'm using the following code:
Sprite * Trees[50];
Layer * Forest;
Forest = [Layer node];
Forest.isTouchEnabled = YES;
[self addChild:Forest z:30];
// do this a bunch of times
Trees[0] = [[Sprite spriteWithFile:#"mytree.png"] retain];
[Trees[0] setPosition:cpv(240,160)];
[Forest addChild:Trees[0] z:5];
And then when I want to destroy a tree I use:
[Forest removeChild:Trees[0] cleanup:YES];
[Trees[0] release];
My problem is that when I look in Instruments, I'm never reclaiming
that memory, there is never a drop back down. I thought that by
releasing the sprite it would free up the memory. Am I doing this
completely wrong?
I know that when you are using the simulator with cocos2d, the memory doesn't look like it's being released, so you have to run it on the device to get an accurate picture of what's going on.
There is a good discussion here about cocos2d and memory.
What I've noticed is that everything that you create and retain must be released, but it isn't released from memory until I do this:
[[TextureMgr sharedTextureMgr] removeAllTextures];
That will release the memory.
Here's a bigger example:
Sprite * sPopup = [[Sprite spriteWithFile:#"popup.png"] retain];
sPopup.position = cpv(240,440);
[self addChild: sPopup z:2];
[sPopup release];
Then, when I'm done with sPopup in another function I have this:
[[TextureMgr sharedTextureMgr] removeAllTextures];
and the memory is freed.
My suspicion is that you are "over" retaining:
Trees[0] = [[Sprite spriteWithFile:#"mytree.png"] retain];
If Trees is a local variable in a function you do not have to retain in that case if spriteWithFile is returning a Sprite with an autorelease.
The section on delay release in the apple documentation discusses this further. The long and short of it is that the receiver of the autorelease is guaranteed to have the object be valid for the duration of its scope. If you need the object beyond the scope of the function (e.g. Trees is a property of a class) then yes, in that case you need a retain (or just synthesize a property configured to retain).
By issuing the extra retain, it is likely that your retain count is always too high (never reaches 0) and hence your object is not garbage collected.
For good measure, I'd suggest reviewing this paragraph as well that talks about the validity of objects.
Even though you call [Trees[x] release], I believe you still need to 'delete' the item from the array, like Trees[x] = nil or something, as the array itself is still containing the object.
The 'retain' in the Sprite creation is also not necessary, as [Forest addChild:z:] will place a retain on it as well (afaik).
Related
I am getting memory leak warnings for these two methods. The second one calls the first one and apparently its leaking memory. Any ideas?
static UIColor *subtreeBorderColor(void)
{
return [UIColor colorWithRed:0.0f green:0.5f blue:0.0f alpha:1.0f];
}
- (void) updateSubtreeBorder
{
CALayer *layer = [self layer];
if (layer) {
// If the enclosing TreeGraph has its "showsSubtreeFrames" debug feature enabled,
// configure the backing layer to draw its border programmatically. This is much more efficient
// than allocating a backing store for each SubtreeView's backing layer, only to stroke a simple
// rectangle into that backing store.
PSBaseTreeGraphView *treeGraph = [self enclosingTreeGraph];
if ([treeGraph showsSubtreeFrames]) {
[layer setBorderWidth:subtreeBorderWidth()];
[layer setBorderColor:[subtreeBorderColor() CGColor]];
} else {
[layer setBorderWidth:0.0];
}
}
}
//3: Potential leak of an object
//6: Calling 'subtreeBorderColor'
//1: Entered call from 'updateSubtreeBorder'
//13: Method returns an Objective-C object with a +0 retain count
//12: Reference count incremented. The object now has a +1 retain count
//6: Returning from 'subtreeBorderColor'
//13: Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1
UPDATE 2: I just completely changed the code and deleted temporary files and cleaned the solution and this is what I see - it is finding errors where there isn't even code
Simple. You don't need the call to - retain in the function. That's exactly what the autorelease pattern is invented for. Since you don't create the UIColor object using alloc-init, you don't take ownership of it. No need to superfluously complicate memory management further. :)
Edit: (to prevent future downvotes) now that you edited your question and code so that it no longer erroneously returns a retained object, the previous statement is no longer valid. Yes, Xcode shows this notice about the memory leak where "there isn't even code", and that's strange. Yes, perhaps a compiler bug. Still, a temporary (and in my opinion, perfectly valid) workaround is to simply use a define instead of a function. Let's see what Xcode says if you write this instead:
#define SUBTREE_BORDER_COLOR [UIColor colorWithRed:0.0f green:0.5f blue:0.0f alpha:1.0f]
If you want to be using "retain" the way you are, you need to also "release" the "UIColor" object you returned from your "subtreeBorderColor" method.
Were this my code, I wouldn't do "retain" on that autoreleased object to begin with. Or better than that, simply do my code with ARC enabled.
both pervious answers are right
but, if for any reason you need to retain an object being returned by your method, please follow the rules and rename your method starting with "new" (or alloc or retain or copy), so everybody (and you too) will know that the returned object is retained, so the calling code knows it's responsable to release it later, when needed...
Which one of these is better practice?
A) retain and release the object myself later
NSMutableArray* array = [[self getArray] retain];
....
[array release];
B) autorelease from the function returning the object
getArray {
NSMutableArray* returnedArray = [[[NSMutableArray alloc] init] autorelease];
.....
return returnedArray;
}
The simplest rule of thumb when it comes to memory management in Objective-C is that you should release anything that you've explicitly allocated (alloc), copied (copy), newed up (new), or retained (retain).
The release should be done within the scope of the aforementioned actions. If you allocate space for an object that is returned by a method, you should autorelease it before returning it. So, given the two options you've provided, B is the recommended practice.
You could read and follow Apples guidelines on memory management and performance.
Personally I think the reasons for choosing one way over the other:
Using Autorelease pros:
You can't stuff it up, memory will be freed at some point. That I like to think of as "falling into the pit of success".
cons:
Using autorelease a lot may cause you memory problems as lots of objects build up awaiting be released by the autorelease pools.
Using retain/release pros:
More control when your memory is used/freed.
On ios apple recommends that you use release instead of autorelease whenever possible to keep the size of the pool small.
cons:
Like C/C++ malloc/free new/delete you have to be careful to keep them matched up and it is easy to stuff that up, causing memory leaks.
For member variables you have no choice, retain/release is it.
I think, whichever style you choose comes down to the situation your code is in and choosing the best style based on there pro's and con's. I don't think there is any one answer to this.
If you want to return an object you have to use the second approach. In all cases where possible you should use the retain-release approach because this uses less memory.
If you new, alloc init, retain, or copy (NARC) an object, you have to release it.
When the name of a method starts with any of those words, it means it's being created for the caller, who has the responsibility to release the object when he is done with it.
Otherwise the method returned is not owned by the caller, and he has to indicate he wants to keep it calling retain on the object.
If you can choose, don't abuse autorelease when memory is a concern.
Some comments:
The first rule logically results in the second. Example: if the outcome of a function (the returned object) survives the execution of the function, all the function can do is autorelease the object.
Unless there is a memory/performance concern, the overhead of automatic memory management is better than the memory leak chances plus the increased developing time.
Try to retain/release symmetrically. Example: if you retained on init, then release on dealloc. Same for viewDidLoad/viewDidUnload.
If you use #property(retain) you have to release in dealloc.
Example:
// created with autoreleased, just call retain if you intend to keep it
NSString *orange = [NSString stringWithString:#"orange"];
// created for the caller, you'll have to release it when you are done
NSObject *apple = [NSString initWithString:#"apple"];
I have an iPhone application in Cocos2d that sometimes crashes on actual device, due to memory problems.
What I have so far found out is that the scenes, when switched, aren't fully released - the [retainCount] for them is somewhat about 4-10 :)
The dealloc method never gets called, and then I assume, when I switch the scenes a few times, the memory issue shows up.
I'm wondering - where should I relese the scene? Since it has number of children, I suppose I should be doing a cleanup-removal of them. But it turns out that removing all children from the layer doesn't decrease the retain count of it. I added such a piece of code to my cleanup method:
- (void) cleanup {
while ([self.children count] > 0) {
CCLOG(#"child: %d - %# rc: %d", 0, [self.children objectAtIndex:0], [[self.children objectAtIndex:0] retainCount]);
[self removeChild:[self.children objectAtIndex:0] cleanup:YES];
}
[super cleanup];
}
But then the [self retainCount] method still returns a number greater then 1 or 0, and my dealloc doesn't get called.
Is there something I should be doing in order to release those children properly? If I add my own subclass of CCSprite as child, should I do something specific in that class' release or dealloc method, other then just calling it's [super] method?
Do not call retainCount
retainCount is useless, as you've discovered, when dealing with complex frameworks. There are any number of internal implementation details that could cause the retain count to be an unexpected value at any given time without indicating a bug.
You should release the scene to balance however many times you retained the scene, no more and no less.
If you release it more times than you retained it, you're app will likely crash whenever you [potentially accidentally] fix the real problem.
In general, when dealing with a hierarchy of items like views, layers, or sprites, you remove the root view/layer/sprite and that removal takes care of tearing down the hierarchy (including releasing as needed).
That assumes that you haven't retained anything in the hierarchy. If you have, then you need to also release those references when the root is removed and released.
Usually you don't have to release your children by yourself. How do you add your child?
I am trying to create a game and have run into what is probably a pretty easy problem to solve.
As the player goes through the game, many objects (Vehicle) will be added and removed.
The Vehicles get added to an array called currentVehiclesMutableArray.
My problem is I cant figure out how to retain a Vehicle so that it remains in the array until I am finished with it.
A NSMutableArray automatically retains anything you add to it.
In fact, you have to make sure you release an object after you added it, or you'll have a memory leak.
For example:
Vehicle *vehicle = [[Vehicle alloc] init];
[mutableArray addObject:vehicle];
[vehicle release]; // you should release it, because it was retained by the array
// at this point, mutableArray holds your vehicle object, and is retaining it
I have some code which I think has extra release statements.
Is the code incorrect?
What is the end result?
I don't understand memory management well yet - even after reading lots of articles and stackoverflow answers. Thanks for straightening me out.
Update: The attached snippet works fine, but other code has the over-release problem
NSMutableArray *points = [NSMutableArray new];
for (Segment *s in currentWorkout.segments) {
[points addObjectsFromArray:[s.track locationPoints]];
}
[routeMap update:points];
[points release];
Your code is correct, but inadvisable. new acts as an implied alloc, which creates the object with a retain count of 1.
I think the last time I used new was in 1992; it's not wrong, but alloc/init is considered better practice, because it is clearer what you are doing. Please read Apple's guide to memory management, it is a comprehensive summary of the situation.
No messages can safely be sent to a deallocated object. Once an object has been released a sufficient number of times, it's deallocated. Any further messages sent to that object are going to an object that isn't there anymore. The precise result isn't completely predictable, but it usually ends in a crash. If you're less lucky, it could end in much stranger ways — for example, you could theoretically wind up with an Object A getting dealloced early and Object B allocated in the same memory location, then Object B receiving messages meant for Object A that Object B does understand but isn't supposed to receive at that time.
Basically, follow the rules. Think of it in terms of ownership. If you've claimed ownership, you need to release that ownership. If you don't own the object, you must not release it.
Take a look at this article online: http://weblog.bignerdranch.com/?p=2 .
It seems to imply that calls to release without a corresponding preior call to retain will result in a BAD_ACCESS error.
A short answer is, if you increasing the retain count of an object and you no longer are using it you should release it, otherwise you shouldnt...
So when ever you do a [objectName alloc] you are increasing the count by 1, when you use such methods as [NSString stringWithString:] these methods return an autoreleased object so you dont need to release it...if you instead did something like [[NSString stringWithString:]retain] then you are increasing the strings retain count and you should release it after you are done using it.
Im not too sure if new increases the reference count (i suspect that it would), you can always check your retain count by doing [object retainCount]... though note that even if the retain count is greater than 0, it does not mean you need to release the object, because some other class might have a reference to the object and therefore has its retain count increased by one and its the responsibility of the other class holding the reference to release it.
Hope this helps
you should use:
NSMutableArray *points = [[NSMutableArray alloc] init];
[...]
[routeMap update:points]; //if routemap stores the points, it will need it's own release retain
[points release]; //if there is a retain in the method above, reference will not be cleared
if unsure, use the build->analyze command, it will search your code for leaked references
you can get the official memory management guide from https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html