I am new to IPhone programming and am I having trouble solving the following memory leak.
while(numDeckCounter < numDecks){
int cardCounter=1;
for (int i =1; i<=52; i++) {
tempCard = [Card new]; //leaks tool says that this is leaking object
if(i>=1 && i<=13)
{
tempCard.suit = CLUBS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard]; //reference count 2
cardCounter++;
}
else if(i>=14 && i<=26)
{
tempCard.suit = DIAMONDS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
else if(i>=27 && i<=39)
{
tempCard.suit = HEARTS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
else
{
tempCard.suit = SPADES;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
if(cardCounter ==14){
cardCounter=1;
}
[tempCard release]; //this causes an EXC_BAD_ACCESS -reference count should be 1
}
numDeckCounter++;
}
I was under the impression that adding an object to the array would increase its reference count by one, then it would be safe to release the object you just added because it would not be deallocated until the array was released bumping which would then release each object in the array. This is when the object should finally be deallocated.
When I add the [tempCard release]; it crashes my app because it can't access the memory location because it has already been deallocated.
From everything I have read, I think what I said above is true. Someone please correct me if I am wrong. Thanks.
I don't see any leaks in the code you presented. (There are some opportunities to slim it down, though, say by moving the identical operations out of the conditionals).
The Leaks tool output is pretty tricky to read. Is it possible that the Card object is leaking one of it's ivars?
Instead of leaks, run static analysis on your product (Product->Analyze). I think it will flag a different part of your code.
Perhaps try [[Card alloc] init] instead of [Card new]. This is just a guess. However trying the IMO more common method of object creation could be helpful.
Check this out: Use of alloc init instead of new
You could also try removing all the code for adding the Cards to the array. So you'd essentially have:
card = [Card new];
[card release];
This could help you find memory issues associated w/ the array retaining the object perhaps?
Related
I use simpleFTP to request document information. I detect memory-leak with instrument as below:
And in the call tree I find out where is the memory leak happened:
The method "_parseListData" as below:
- (void)_parseListData
{
NSMutableArray * newEntries;
NSUInteger offset;
// We accumulate the new entries into an array to avoid a) adding items to the
// table one-by-one, and b) repeatedly shuffling the listData buffer around.
newEntries = [NSMutableArray array];
assert(newEntries != nil);
offset = 0;
do {
CFIndex bytesConsumed;
CFDictionaryRef thisEntry;
thisEntry = NULL;
assert(offset <= self.listData.length);
bytesConsumed = CFFTPCreateParsedResourceListing(NULL, &((const uint8_t *) self.listData.bytes) [offset], self.listData.length - offset, &thisEntry);
if (bytesConsumed > 0) {
........
}
I don't know how to fix this problem.
The method "CFFTPCreateParsedResourceListing" is a system method and it create __NSDate (look at the second pic).
This is where the memory-leak happen.
The CFFTPCreateParsedResourceListing function returns a CFDictionary into the thisEntry variable, which presumably contains the NSDate objects.
The code should call CFRelease on thisEntry once it is finished with it:
// once we're done with thisEntry
if (thisEntry) {
CFRelease(thisEntry);
}
Old post, but useful solution. You can find the answer here BlackRaccoon ftp client.
According to the creator the CFFTPCreateParsedResourceListing method retains twice the NSDate, to override the issue add the next code, be aware of the comments here:
FAQ section
"Actually, in WhiteRaccoon, if you list a directory you will leak NSDate's. The function CFFTPCreateParsedResourceListing in Apple's SDK has a leak in it. I've attempted to "patch" this, however it isn't guaranteed to work. For OS 5.1 it does work."
........
if (parsedBytes > 0)
{
if (listingEntity != NULL)
{
//----- July 10, 2012: CFFTPCreateParsedResourceListing had a bug that had the date over retained
//----- in order to fix this, we release it once. However, just as a precaution, we check to see what
//----- the retain count might be (this isn't guaranteed to work).
id date = [(__bridge NSDictionary *) listingEntity objectForKey: (id) kCFFTPResourceModDate];
if (CFGetRetainCount((__bridge CFTypeRef) date) >= 2)
CFRelease((__bridge CFTypeRef) date);
this works for me
I am using TBXML for XML feed parsing and instruments to detect memory leaks.
Instruments tells me there is a memory leak in function
- (TBXMLAttribute*) nextAvailableAttribute {
currentAttribute++;
if (!currentAttributeBuffer) {
currentAttributeBuffer = calloc(1, sizeof(TBXMLAttributeBuffer));
currentAttributeBuffer->attributes = (TBXMLAttribute*)calloc(MAX_ATTRIBUTES,sizeof(TBXMLAttribute));
currentAttribute = 0;
} else if (currentAttribute >= MAX_ATTRIBUTES) {
currentAttributeBuffer->next = calloc(1, sizeof(TBXMLAttributeBuffer));
currentAttributeBuffer->next->previous = currentAttributeBuffer;
currentAttributeBuffer = currentAttributeBuffer->next;
currentAttributeBuffer->attributes = (TBXMLAttribute*)calloc(MAX_ATTRIBUTES,sizeof(TBXMLAttribute));
currentAttribute = 0;
}
return ¤tAttributeBuffer->attributes[currentAttribute];
}
at the line
currentAttributeBuffer->attributes = (TBXMLAttribute*)calloc(MAX_ATTRIBUTES,sizeof(TBXMLAttribute));
Does any one solved it before?
BEWARE.... instruments is telling you WHERE the leaked memory was originally created, NOT that the issue is in that line... for instance, if you do something with the attribute returned and leak it elsewhere, instruments will show THE line above, where it was created, NOT where you leaked it....
calloc is a C function to allocate memory. You should call free currentAttributeBuffer; when you're finished with it. That will fix the memory leak.
I am working on a game in Cocos2d for iPhone.
In my init method I have an object (type id) declared as follows (also note bossDir is declared as 1):
bossMov = [CCMoveTo actionWithDuration:1.0f position:ccp(75*bossDir, 320-55)];
[boss runAction:bossMov];
Then in a timer method I have:
if ([bossMov isDone] == YES) {
bossDir = -bossDir;
[boss stopAllActions];
[boss runAction:bossMov];
}
It moves the boss once, but after that it gives EXC_BAD_ACCESS and points me to a line in the file "CCTimer.m" that says:
if( elapsed >= interval ) {
impMethod(target, selector, elapsed); //This line in particular.
elapsed = 0;
}
How can I fix this problem?
have you tried the NSZombieEnabled because i am not a cocos2d guy but just as a suggestion i am telling you this. Because bad access error comes only when you are pointing to an object which is no longer in the memory and the application crashes if you try to do so
You are not retaining bossMov action. So when you call [boss stopAllActions]; it is released and deallocated. Then you are trying to run the deallocated action - so you get the bad access.
I have one MutableArray (NSMutableArray *NoteBook;) in which I would like to store Notepages (I set up an object called NotePage.m which simply contains one NSString *noteText and a method to setNoteText). I also have an integer to keep track of my pages (NSUInteger currentPageCounter;).
I start my little program by setting up a new instance of NotePage:
NotePage *newPage = [[NotePage alloc] init];
[newPage setNoteText:#"Sample Text for a certain page..."];
I then copy this *newPage 3 times into my NoteBook Mutable Array:
[self.NoteBook insertObject:newPage atIndex:(self.currentPageCounter)];
This will give me 3 pages, at the indices 0,1,2. So far so good. Everything works splendid. But now comes the enemy, UITextView. First of all, I would like to display the contents of a page within my NoteBook in an UITextView. So I did this to sync one section in the MutableArray (e.g. page at index 0) with the UITextView which works fine:
NotePage *thisPage = [self.NoteBook objectAtIndex:self.currentPageCounter];
TextViewNote.text = thisPage.noteText;
The problem is, however, if I want to edit my UITextView and sync the updated text with the MutableArray. This is where the crashing happens... I have coded this in a separate method which can be clicked once the user is done editing the UITextView:
-(IBAction) savePage
{
NSString *tempString;
tempString = [NSString stringWithFormat:#"%#",TextViewNote.text];
NotePage *newPage = [[NotePage alloc] init];
[newPage setNoteText:tempString];
[self.NoteBook insertObject:newPage atIndex:(self.currentPageCounter)]; // e.g. at index 0 for page 1
[self.NoteBook removeObjectAtIndex:(currentPageCounter+1)]; // i.e. this is to remove the old page 1 which used to be at index 0 but now is at index 1
[self syncTextView];
[self syncCounter];
}
I guess there is a less cumbersome way (I'm still a beginner...) to simply replace an object at a certain index at a Mutable Array. As it stands now, it will simply crash once I try to move onwards to the next index position which is apparently not found anymore.
Thanks for any ideas!
I guess there is a less cumbersome way
(I'm still a beginner...) to simply
replace an object at a certain index
at a Mutable Array.
Indeed. Look at -[NSMutableArray replaceObjectAtIndex:withObject:].
Considering the error you posted, it sounds like you've got a bad pointer somewhere. The error is complaining that somewhere, a -[UITouchData length] message is being sent to an instance of NotePage. Turn on the 'Stop on Objective-C Exceptions' option in the debugger (under the Run menu). That should help you see where the problem is occurring.
NSMutableArray has a method replaceObjectAtIndex:withObject: that should do what you are trying to do.
You've got a memory management issue, however, unless you are calling release on the newPage after you add it to the array. Unless you are planning on making the NotePage class more complex, it might make sense simply to change the item's text rather than substituting a new object:
[[self.noteBook objectAtIndex:currentPageCounter] setNoteText:tempString];
(Also, be aware that inserting the newPage object into the array four times does not copy the object; it simply inserts the same reference four times. If you want four distinct objects, you will need to allocate four objects in a loop:
for(i = 0; i < 4; i++){
NotePage *newPage = [[NotePage alloc] init];
[newPage setNoteText:#"Dummy text"];
[self.notebook addObject:newPage];
[newPage release];
}
I have the following instance method (adapted from Listing 3-6 of the Event Handling section in the iPhone Application Programming Guide):
- (CGPoint)originOfTouch:(UITouch *)touch
{
CGPoint *touchOriginPoint = (CGPoint *)CFDictionaryGetValue(touchOriginPoints, touch);
if (touchOriginPoint == NULL)
{
touchOriginPoint = (CGPoint *)malloc(sizeof(CGPoint)); // leaks
CFDictionarySetValue(touchOriginPoints, touch, touchOriginPoint);
*touchOriginPoint = [touch locationInView:touch.view];
}
return *touchOriginPoint;
}
Every once in a while my app leaks 16 Bytes as a result of the call to malloc(). I'm not sure how to return touchOriginPoint while free()ing it as well.
If you do not care a minor performance loss, use an NSMutableDictionary and store the point as an NSValue:
NSValue* touchOriginPointValue = [touchOriginPoints objectForKey:touch];
if (touchOriginPointValue == nil) {
touchOriginPointValue = [NSValue valueWithCGPoint:[touch locationInView:touch.view]];
[touchOriginPoints setObject:touchOriginPointValue forKey:touch];
}
return [touchOriginPointValue CGPointValue];
If you must use the CFDictionary approach, you have to find a place to free those malloc-ed memory when the values are not needed. Therefore, you have to pass the values callbacks when creating the dictionary
static void free_malloced_memory (CFAllocatorRef allocator, const void *value) {
free((void*)value);
}
static const CFDictionaryValueCallBacks values_callbacks = {0, NULL, free_malloced_memory, NULL, NULL};
...
touchOriginPoints = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, & values_callbacks);
...
If you must return the malloc'd value from the function, then you have passed the responsibility for freeing the memory to the calling function, or one of its callers.
Since we can't see the calling functions, we can't diagnose any more.
If you are going to be returning an object that is allocated, then either you need to have the caller free() it, or else you need to be using some kind of garbage collection (so it gets freed automatically).
you don't actually return a pointer, the value is copied to a temp value when it is returned, so you aren't really returning the allocation at all, the problem is that you just aren't freeing it either, you add the allocation to the dictionary and just leave it there?
is there like an EndOfTouch function? where you remove the touch from the dictionary? if there is, call free on your allocation there and you should be fine