iPhone - Memory leak while displaying UILabel - iphone

I am using a simple function to display messages to user through a label. The function is as follows:
-(void) showMessage:(NSString*) message
{
Message.text = message;
[message release];
}
There is no memory leak if I call this function from the main thread. But if I call this function from a separate thread, the instruments monitor shows a 16 byte memory leaks as soon as the function is called. The leak is not seen if I comment out the function call. Does anyone know why ? I am using iPhone SDK 3.0. The instruments monitor does not point to any of my functions to indicate the leak. It only shows a function or two from UILabel.

Looking at your code there, it seems you've got memory management wrong somewhere - you should never release an object you receive as a method parameter. Consider the following:
-(void)doSomething {
NSString *aStr = [[NSString alloc] init];
[self showMessage:aStr];
NSString *anotherStr = [aStr stringByAppendingString:#"Hi"];
// ^^ This call will crash as aStr has been released and is invalid.
}
-(void) showMessage:(NSString*) message {
Message.text = message;
[message release];
}
... Using your method in the above example will cause a crash, because the showMessage: method releases the passed string.
I know this doesn't directly answer your question, but get memory management right and your problems may well go away. I suggest you read Apple's Memory Management Programming Guide for Cocoa.
Edit: Also, UIKit isn't thread-safe - you should never call a message to a UIKit object from anything but the main thread. See performSelectorOnMainThread:withObject: for calling a message on the main thread from another thread.

It is hard to make out from this piece of code. Also, instruments is not a perfect mechanism, certainly not for finding (and solving) leaks of this size..
It is probably not even a leak, but that depends on how you initialize and release the message string before and after the function call.
If you initialize it like this;
NSString *message = [[NSString alloc] initWithString:#"hello"];
Message will receive a retain count of +1, and you have to release it after you've passed it as a parameter to your function.. Inside the function it will be retained again by the label. If you initialized it with an autorelease message, then it's a whole different story.
Also, when you are working with NSThread, use the NSAutoreleasePool in your methods.
I'd also suggest running XCode's static analyzer, which may help you find improper memory management.

Related

why is there a memory leak in the SimpleEKDemo code?

When profiling the SimpleEKDemo application from Apple I note there are some memory leaks.
One of the leaks is __NSArrayM which has 3 lines in the Leaked Blocks history, a Malloc/Assign/Release.
Question - can someone point out the root cause issue here? (I'm trying learn how to take Instruments output of where a leaky object was created, and then from there work out root cause, so this would be really useful)
You will notice that when you run the demo with leaks that there is a leak in viewDidLoad (responsible frame). If you switch to Call Tree detail and if you have enabled Invert Call Tree, you will see a leak associated with the call +[NSArray new]. If you open that a bit, you will see initWithArray which is called in the RootViewController's viewDidLoad. The problem bit is,
self.eventsList = [[NSMutableArray alloc] initWithArray:0];
eventsList is a retained property so the object created has a retain count of 2. However it is only released once either through the release in dealloc or through reassignment of eventsList. YOu will have to autorelease this object.
self.eventsList = [[[NSMutableArray alloc] initWithArray:0] autorelease];
Once fixed, you shouldn't get any errors.

Memory problem with this code

Hi all i have a problem in understanding the concept of retain in following example.i know about usage of retain...but confused here..
i have 2 classes View1 and View2
here is method of View1
-(IBAction)callingView2
{
view2 *view=[[view2 alloc] init];
[self.navigationController pushViewController:view animated:YES];
NSString *ss=[[NSString alloc]initWithString:#"Hi friend"];
[view callingToRetain:ss];
[ss release];
[view release];
}
and in view2 i have 2 methods and str is a string(not allocated)
-(void)callingToRetain:(NSString*)s
{
//[s retain]; //it is not effecting my program
str = s;
}
//And then printing it on a button click after reaching to view2
-(IBAction)print
{
NSLog(#"string = %#",str);
}
The rules says that i should retain the string if i have to use it later, but here it's working without retain.....
I thing this is due to str = s; because it is retaining to MAX_VALUE, but i am not sure...
if this is the problem then does it effects the memory leak concept ?
Any suggestions?
The rule only says you need to retain if you need to use an object later.
It does not say if you fail to retain correctly, it will definitely crash.
Most often, not retaining correctly leads to a crash sooner or later. But your code is an exception, because the string you used was just a constant string known at a compile time.
What's going on is this. Suppose you perform the following operation:
NSString* s=#"foo";
NSString* ss=[[NSString alloc] initWithString:#"foo"];
This in fact makes ss equal to s. As an optimization, the Cocoa runtime does not create a separate NSString instance.
And this object s is a compile-time NSString, which effectively behave like an infinitely-retained object.
That's why your code didn't crash. However, Apple can change the Cocoa runtime implementation in the next version of the OS so that your code does crash.
The point is that you should follow the rule. If you follow the rule, it doesn't crash even in a future version of the OS. If it doesn't, it might not lead the crash immediately, but it eventually will.
Even if it's working without retain, you should use it (or better yet, copy it). That's the rule. That doesn't mean it will work in the future, or with other calls.
Also, don't forget to release it on dealloc.

Memory leaks caused due to CoreFoundation Framework

I am developing an iPhone application which mainly makes use of the Address Book and database. After fetching about 3000 contacts from the address book, I am attaching string tags to the contacts (5 for each). I am saving my tags in the database.
For Load testing purpose i have added 10,000 tags to the App. But during the load testing of my application, I observed some memory leaks which were not related to the Application code but represents a set of Instruction sets. Also Instruments showed Foundation as the responsible library for the Leak (Extensive use of NSString,NSDictionary,NSArray which belongs to the Foundation framework). My application crashes after 10 - 15 mins of usage.The Crash report mentions, application crashed due to low memory.
Memory profiling using CLANG shows zero leaks. How do i solve these memory leaks?
Are these leaks the real culprit behind the crash? Are there any other tools available to check memory leaks?
I often find my leaks say they're caused by Core Foundation (or any other framework for that matter) but are really my own. With the exception of the Simulator, rarely will you find excessive leaking in the frameworks.
If you open up the detail panel to the right in Instruments you may find listed your App's methods in there. That will give you indication of where it could be coming from in your code. One leak can spring many other leaks, and you may have to find the top level culprit to get rid of the lower level ones.
You should not expect Clang to do anything but find the most obvious leaks. It's very handy, but that's it, just a helpful addition to compiling.
clang is not a leak checker. It only detects a small subset of issues.
For memory leak debugging you should focus on Instruments, specifically the Object Allocation and Leaks instruments. Be sure to understand the difference between leaks and other source of high memory usage though.
Once you've determined that objects are leaking, use Instruments to examine their allocation stack trace (so you can tell what object it is), and their retain/release history.
If it's not a leak, then I suggest investigating the instructions here:http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/
Most likely you have code that is creating the foundation objects. Leaks shows you the place of allocation but that is generally due to a call your code made to create the object. You can look at the call chain in Instruments and go back along the call chain until you get to your code - that is the place where you are causing the allocation. Now, for that allocation, look at your memory handling for that object: Do you release it some time later?
There are lots of ways you can fail to release memory property so it would be hard to guess which one you might be hitting. Ones I see when helping people include allocating an object and assigning it to an instance variable via a property with the retain attribute, something like this:
#property (retain) NSString* myString;
...
self.myString = [[NSString alloc] initWithString: #"foo"];
the alloc+init creates a retained object, the self.myString = increments the retain count again. If coded correctly, the dealloc method releases the property via one of:
[myString release];
or
self.myString = nil;
And that takes care of the retain added with the self.myString = but does NOT take care of the retain from creation. Solutions, ONE of the following:
myString = [[NSString alloc] initWithString: #"foo"]; // doesn't call the setter method so no assignment retain - but doesn't call the setter which might be bad if non-trivial setter.
self.myString = [[[NSString alloc] initWithString: #"foo"] autorelease];
autorelease releases the alloc+init retain.
Now of course this is a contrived example because you'd probably really use:
self.myString = [NSString stringWithString: #"foo"];
which is a class method returning an autoreleased string and avoids the problem. But the idea is to show a simple example to explain this type of issue.
There are many other ways to not release memory properly, but the advice to work your way back up the call-chain until you get to your code is the way to go look at where you are triggering the allocation of the memory and then you can figure out why you aren't releasing that properly.
Try to do some issues in u code:
1. Please avoid hide declaration like
NSString *string = [dictionary valueForKey:[dictionary2 valueForKey:#"something"]]
Correct code is:
NSString *key = [dictionary2 valueForKey:#"something"];
NSString *string = [dictionary valueForKey:key];
key = nil;
Try to avoid declaration with autorelease and local declaration like:
NSArray *array = [NSArray array];
If u do this, make sure that u have:
NSArray *array = [NSArray array];
.... some code where array is using;
array = nil;
Better idea is alloc and release immediately when u don't need object and put it to nil.
3. Check if u using correct setters. Probably better idea is avoid to using it, at my experience, deallocate class start leaks for getters and setters, which was using before.
If u post some part of u code, where u seen most leaks (instruments give u possibility to click on leaked objects and see volume of leaks in programming code) community can suggest more.

stringWithContentsOfURL leaking memory

Would it shed more light if I told that fetchHTML was being called in a seperate thread? I am also seeing several messages in the debug console such as:
_NSAutoreleaseNoPool(): Object 0xd92860 of class NSCFDictionary autoreleased with no pool in place - just leaking
_NSAutoreleaseNoPool(): Object 0xd92800 of class NSCFString autoreleased with no pool in place - just leaking
I am new to iPhone app development, Objective-C but not new to programming or C/C++. I am using the leaks performance tool and it shows many leaks. This is a 10.5 kb leak and it occurs on the line:
NSString * xml = [NSString stringWithContentsOfURL:urlobj];
The stack trace on this below is:
stringWithContentsOfURL
initWithContentsOfURL
initWithDataOfEncoding
...
Does anyone have an idea why this must be happening. I am under the impression that I get an autorelease object here and I can return this to the caller without calling retain. I am not using the xml object to store in an instance variable, just for processing.
Here is the function code:
- (NSString *) fetchHTML: (NSString* ) url{
#try
{
NSURL* urlobj = [NSURL URLWithString:url];
NSString * xml = [NSString stringWithContentsOfURL:urlobj];
return xml;
}
#catch( NSException *ex){
NSLog(#"Error fetchingHTML");
return nil;
}
return nil;
}
Yup; that shouldn't be leaking.
It might be a false positive in that the URL subsystem is caching the contents of the URL and doing so in a way where the pointer is no longer visible to leaks analysis.
If you can, retry the test on Snow Leopard. Leaks detection on Snow Leopard is significantly faster and more accurate.
I completely agree with you that this should not cause a leak. I've been coding in Cocoa/Objective-C for 2 years now, and that looks like it should work.
That being said, I notice that Apple's documentation indicates that the stringWithContentsOfURL: method is being deprecated. Perhaps it would work as follows:
NSString * xml = [[NSString alloc]
initWithContentsOfURL:urlobj
encoding:NSASCIIStringEncoding
error:nil];
return [xml autorelease];
As the error message says, there's no autorelease pool for the string to go into, and that creates a leak. NSAutoreleasePools exist on a per-thread basis. Cocoa creates one in the main event loop of the main thread, but that's the only one it creates for you. If you're somewhere other than the main thread and you're going to be dealing with autoreleased objects, you need to create an autorelease pool for that thread as well.
You can check out the NSAutoreleasePool docs for more information on how autorelease pool stacks work.

Why am i getting a EXC_BAD_ACCES

Hey. I have been working on a Twitter application and have been stuck on a EXC_ BAD_ ACCESS error for quite some time. I know that EXC_ BAD_ ACCESS is a memory issue but i cannot pinpoint where the problem is. Here is my code sample:
- (void)viewDidLoad {
[super viewDidLoad];
NSString *path = #"/Volumes/Schools/BHS/Student/740827/Documents/Forrest McIntyre CS193P/Presence2";
NSArray *propList = [NSArray arrayWithContentsOfFile:[NSBundle pathForResource:#"TwitterUsers" ofType:#"plist" inDirectory:path]];
people = [[NSMutableArray alloc]init];
for (NSString *name in propList) {
Person *p = [[Person alloc] initWithUserName: name];
[people addObject: p];
[p release];
}
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
The exception is thrown on the last brace after the comment. I believe that it is truly thrown in the for loop somewhere but just shows up upon exiting.
Here is the implementation file for Person:
#implementation Person
#synthesize image;
#synthesize username;
#synthesize displayName;
#synthesize statusArray;
-(id)initWithUserName:(NSString *)userName {
if(self = [super init])
{
self.username = userName;
NSDictionary *info = [TwitterHelper fetchInfoForUsername:userName];
self.displayName = [info objectForKey:#"name"];
NSLog([NSString stringWithFormat:#"%#",[info objectForKey:#"profile_image_url"]]);
NSString *imageURL2 = [NSString stringWithFormat:#"%#",[info objectForKey:#"profile_image_url"]];
self.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString: imageURL2]]];
[info release];
self.statusArray = [TwitterHelper fetchTimelineForUsername:userName];
}
return self;
}
#end
Thanks for any help
EDIT: Here is the header file for PersonListViewController (the class that contains the ViewDidLoad).
This is just to show you where people is coming from.
#interface PersonListViewController : UITableViewController {
NSMutableArray *people;
}
#end
since you never retain propList or path you shouldn't be releasing them.
You should, however, release people
For an overview of memory management, see the Memory Management Programming Guide
For quick fixes, try the static analyzer.
I think the problem is here:
[propList release];
Since you created propList using arrayWithContentsOfFile you don't need to release it - it will be automatically released. The autorelease is actually what's causing the error since it is trying to release something that you already released manually.
ETA: as cobbal mentioned, you also don't need to release path.
Debugging EXC_BAD_ACCESS is difficult to debug. This happens when a message is sent to an object that is already released. You need to find out what is causing this generic error by turning on NSZombiEnabled environment variable so the Objective-C environment will be able to 'track' a deallocated object. Using this, when you get the error you can determine where the error occurred by looking at the call stack. You won't know where it is released but at least it will get you close.
I don't have it setup here, but you may also be passing a pointer to the error which will cause the object to not persist as a zombie/dummy.
Bottom line, you need to make sure the variables you are meaning to release, that you retain them as necessary.
This Technical Q&A by Apple gives tips on Finding bugs with EXC_BAD_ACCESS.
For one, neither of these are necessary in your example:
[path release];
[propList release];
because:
path is a string literal (will always exist)
propList is autoreleased
For any EXC_BAD_ACCESS errors, you are usually trying to send a message to a released object. The BEST way to track these down is use NSZombieEnabled.
This works by never actually releasing an object, but by wrapping it up as a "zombie" and setting a flag inside it that says it normally would have been released. This way, if you try to access it again, it still know what it was before you made the error, and with this little bit of information, you can usually backtrack to see what the issue was.
It especially helps in background threads when the Debugger sometimes craps out on any useful information.
VERY IMPORTANT TO NOTE however, is that you need to 100% make sure this is only in your debug code and not your distribution code. Because nothing is ever released, your app will leak and leak and leak. To remind me to do this, I put this log in my appdelegate:
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
NSLog(#"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
If you need help finding the exact line, Do a Build-and-Debug (CMD-Y) instead of a Build-and-Run (CMD-R). When the app crashes, the debugger will show you exactly which line and in combination with NSZombieEnabled, you should be able to find out exactly why.
http://www.cocoadev.com/index.pl?NSZombieEnabled can be useful in tracking down EXC_BAD_ACCESS bugs. Instead of deallocating objects when they are released it puts them into a zombie state that raises an exception when they are subsequently accessed. Just be sure not to ever release code with this flag set, as it will leak memory like a sieve.
what is self.editButtonItem? I don't see it in your .h file
A couple of things.
In initWithUserName: you're getting info from a method that doesn't contain alloc/copy/create. Further, you don't explicitly retain it. Yet you release it. This is problematic assuming fetchInfoForUsername: autoreleases its result as expected according to the Cocoa Memory management rules.
Using property accessors in initializers is considered bad form since it can cause KVO notifications to be sent out for a half-baked instance.