Memory leak in stringByAppendingString - objective-c

NSString *strURL=#"http://cache.finn.no/mmo/";
strURL=[strURL stringByAppendingString:soapResults];
[arrMainImages addObject:strURL];
My last two lines are causing memory leaks? Here, the variable soapResults is of type NSMutableString.

The snippet above looks fine regarding how you are using strURL - how do you actually know that there are leaks occuring in those lines?
You might want check though that you are releasing soapResults and arrMainImages properly if you took ownership of them.

Related

Objective-C Memory Leaks

I'm just investigating some memory leaks in my app, I'm using Xcode 4.0.2. I've run the Analyze tool in Xcode and a good few memory leaks have been identified. I'm relatively new to Objective-C, this is my first app. I've pasted the code here:
http://pastie.org/3155043
I've added comments to the above code, where the memory leaks are occuring.
Memory Leak One: Method returns an Objective-C object with a +1 retain count (owning reference).
Memory Leak Two: Object allocated on line 248 and stored in 'imagesNames' is not referenced later in this execution path and has a retain count of +1 (object leaked).
Memory Leak Three: Potential leak of an object allocated on line 246 and stored into 'cmpWordoutStr'.
Any help appreciated.
Regards,
Stephen
You might want to consider using Automatic Reference Counting in your project.
I asked a question the other day on here, as I wasn't sure that it was a good idea, but the answers convinced me that it really is a step forward and is well worth taking advantage of:
To ARC or not to ARC? What are the pros and cons?
Hope this helps :)
Leak 1) You don't show the return or identify which variable is returned, so not possible to definitively diagnose this one.
Leak 2) You alloc/init an NSString and assign it to a variable that is never released. This is wrong for two reasons:
For each alloc there must be a corresponding release somewhere.
There is no point in doing alloc/init on an empty string. If you want an empty string just use #"".
Leak 3) Basically the same as (2).
(You really need to get a good book on Objective-C programming and study and restudy the section on storage management. Otherwise you'll be stumbling around in the dark.)
You're allocating an object first
NSString *cmpWorkoutStr = [[NSString alloc] init];
and then reassign the pointer without freeing the memory:
cmpWorkoutStr = [cmpWorkoutStr stringByAppendingString:indWorkoutStr];
hence the leak.
I didn't analyze your code in depth, but I guess you actually want NSMutableString there.
As Tom Andersen suggested above I used auto release and this solved the problem, example below:
NSString *cmpWorkoutStr = [[[NSString alloc] init] autorelease];
NSString *imageNames = [[[NSString alloc] init] autorelease];
Regards,
Stephen

Object release behavior in iPhone

If I release mainPath in following example the program gives an error (because I’m releasing an object with zero counter)
NSString *mainPath = [NSString stringWithFormat:#"%#/Documents/downloadFile.plist",NSHomeDirectory()];
NSLog(#"address is = %#",mainPath);
[mainPath release]; //Program failed here
But the following code works fine.
NSString *aa=#"hiiiii";
[aa release];
Can anyone explain this?
Actually I’m not clear about the pointer concept (give a suitable link to clear it)
Constant NSStrings are a special case. They are allocated statically at compile time and can't be deallocated. You can send release to a constant string as many times as you like, it'll never get deallocated. This is achieved in the current implementation by setting the retain count to INT_MAX which is treated as a special value meaning "don't decrement me on release".
You should read the Cocoa Memory Management Guide or at least the Objective-C Tutorial by Scott Stevenson. (Really. Do it, you’ll save a lot of time in the long run.) The difference is that the first string is autoreleased, you do not own it and should not release it. The second string is special, I think it’s not allocated on the heap at all and the release is essentially a no-op here.
String with format is a convenience method that autoreleases the string so in this case you are likely to be sending a release message to an already deallocated object.
In your second example, you are creating the string statically so retain counts don't apply.
You don't need to release your objects in either of those cases.
As a rule of thumb, if you didn't use init (or initWithFoo:) to create the object, and didn't deliberately use retain to retain the object (plus couple of other rarer cases), you don't need to use release.

Code Example: Why can I still access this NSString object after I've released it?

I was just writing some exploratory code to solidify my understanding of Objective-C and I came across this example that I don't quite get. I define this method and run the code:
- (NSString *)stringMethod
{
NSString *stringPointer = [[NSString alloc] initWithFormat:#"string inside stringPointer"];
[stringPointer release];
[stringPointer release];
NSLog(#"retain count of stringPointer is %i", [stringPointer retainCount]);
return stringPointer;
}
After running the code and calling this method, I notice a few things:
Normally, if I try to access something that's supposedly dealloced after hitting zero retain count, I get a EXC_BAD_ACCESS error. Here, I get a malloc "double free" error instead. Why is that?
No matter how many lines of "[stringPointer release]" I add to the code, NSLog reports a retain count of 1. When I add more releases I just get more "double free" errors. Why aren't the release statements working as expected?
Although I've over-released stringPointer and I've received a bunch of "double free" errors, the return value still works as if nothing happened (I have another NSLog in the main code that reports the return value). The program continues to run normally. Again, can someone explain why this happens?
These examples are fairly trivial, but I'm trying to get a full grasp of what's going on. Thanks!
You're getting a double free error because you are releasing twice and causing two dealloc messages. =P
Keep in mind that just because you release doesn't doesn't mean the data at its memory address is immediately destroyed. It's just being marked as unused so the kernel knows that, at some point in the future, it is free to be used for another piece of data. Until that point (which is totally nondeterministic in your app space), the data will remain there.
So again: releasing (and dealloc'ing) doesn't necessitate immediate data destruction on the byte level. It's just a marker for the kernel.
There are a couple of things going on here. First, deallocing an object doesn't necessarily clear any of the memory the object formerly occupied. It just marks it as free. Unless you do something else that causes that memory to be re-used, the old data will just hang around.
In the specific case of NSString, it's a class cluster, which means that the actual class you get back from alloc/init is some concrete subclass of NSString, not an NSString instance. For "constant" strings, this is an extremely light-weight structure that just maintains a pointer to the C-string constant. No matter how many copies of that striing you make, or how many times you release it, you won't affect the validity of the pointer to the constant C string.
Try examining [stringPointer class] in this case, as well as in the case of a mutable string, or a formatted string that actually uses a format character and arguments. Probably all three will turn out to have different classes.
The retainCount always printing one is probably caused by optimization - when release notices that its going to be deallocated, there's no reason to update the retainCount to zero (as at this point nobody should have a reference to the object) and instead of updating the retainCount just deallocates it.

Object not releasing objective C

I am having trouble understanding why NSLog reports "dog" when the code is run. I understand about retain counts and dealloc e.t.c. What simple thing am i missing ?
NSString *newFoo = #"dog";
[newFoo release];
NSLog(newFoo);
[#"String Literal" release];
is a noop;
NSString *literal = #"String Literal";
[literal release];
is also a noop. This is only the case for string literals; and you should never expect this behaviour anywhere else. (This is to say; even though you tell the object to release, it just doesn't.)
I believe it's because #"dog" is effectively treated as a constant by the compiler. It creates some subclass of NSString (which is a class cluster) which persists for the lifetime of the application.
Just discovered this question for the definitive answer, which is essentially the same as mine.
A String Literal is a special case.. http://thaesofereode.info/clocFAQ/
But in general assuming you are not using garbage collection just stick to the few simple rules..
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
more pertinently.. retain an object when you need it to stick around - balance it with a release when done. If you didn't create or retain it, you don't need to release it.
Sending -release to an object isn't like freeing the memory, it only signals that you are done with it. It may well still be around or it may not. You have no way of knowing, you don't need to know, and you shouldn't try to find out if it is used elsewhere, if clever apple code has decided to cache it, if it's a singleton, etc.
It may well still be valid but when you have sent release you have effectively said "I'm done" and not "reclaim this memory".
You are de-allocating the chunk of memory the pointer's pointing at, but the data is still there.
Releasing it doesn't automatically zeroes out that part of the memory.
So you can still read the data out just fine but it's just might be snapped (allocated) by something else down the line... but just not yet.
I'm not an ObjC coder by trade but as since its compatible with C that's I'm guessing from my C experience.
Although the object is probably released (not sure how Obj-C handles strings internally, some languages basically cache strings), you have not writted anything new in the memory of newFoo after you released it. The memory where the string was stored keeps its content, but could be overwritten at any time.
newFoo still points to the same adress in memory, but that memory could become anything else at any moment.
The way to really be sure that you don't point to potentially dirt memory is to set newFoo to nil after you released it.

What might cause half of an NSData object to stay in memory after releasing it?

I'm loading a series of images from a server into NSData objects like so:
for (int i = 0; i < 36; i++)
{
NSURL *url = [NSURL URLWithString:#"http://12.34.56.78/image.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
// Further processing here
}
The problem is that half of each data object is being kept in memory. This does not show up as a leak in instruments. I know it's the NSData object because I have removed everything having to do with images and really only have the two lines before the comment now. The same behavior occurs. I've tried alloc initing and releasing explicitly with the same result.
The thing that makes this really hard to figure out is that I created a second project to try to recreate this behavior and I can't get it to do so. In the other project, this code acts as expected. So I'm asking, what might cause such behavior? I feel like I'm overlooking something extremely obvious.
From the two lines you have written, that data object should never leak because you are not retaining it, when you go out of scope that d ata object should autorelease...So cant really tell from the two lines you have posted..
I have encountered something similar where I had an array in my AppDelegate and I was grabbing a reference to a single row then (mistakenly) releasing my handle on the object. The result was that after 3 subsequent calls, the object in the row in question had nil values in all properties but itself was not nil. Took me about a week to figure that one out. To this day I still have no idea why it took 3 calls to release before I noticed a problem. I'm sure you can imagine my frustration when a week later I realized that one line of code was the source of 20 or so wasted hours. ;)
If what you're seeing is steadily growing memory, use Instruments' Object Allocations probe, and look for what is actually holding the memory. There are many ways to waste memory in ways that are not a "leak." The fact that the size is half the NSData size suggests that you're looking in the wrong place. It is unlikely that you are freeing half an object.