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.
Related
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.
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.
In the code below, PersonListArray is an NSMutableArray and I'm getting the list of persons from the sqlite DB and adding it to my array.
Person* tmpPerson = [[Person alloc] init];
tmpPerson.personName = #"Mike";
tmpPerson.personEmail = #"mike#mike.com";
[PersonListArray addObject:tmpPerson];
[tmpPerson release];
Even though I'm releasing the Person object here, its giving a memory leak which I'm guessing is due to the array holding a reference count to it. I'm using the array elsewhere in the program and then releasing it for sure.
What's the best practice to create new objects for an array and not run into this issue?
In the dealloc method where i release the array
-(void) dealloc{
[PersonListArray release]; // this contains the numerous Person objects
[super dealloc];
}
should i manually release them like this instead ?
-(void) dealloc{
for (int i = 0; i<PersonListArray.count;i++)
{
Person * tmpPerson = [PersonListArray objectAtIndex:i];
[tmpPerson release];
}
[PersonListArray release];
[super dealloc];
}
The code you are showing us is correct and contains no leaks. The last section is wrong, though, and would case your program to crash because you are releasing Person objects you no longer own.
Your code, as initially implemented, is correct. An array retains onjects added to it and releases them either when they're removed from the array or when the array is dealloced. No need to go through the array yourself.
What means are you using to detect the leak? If it's Instruments then you may be misunderstanding what it is telling you. When it detects a leak, it can show you where the memory was first allocated. It can't show you which object is responsible for the leak. I would therefore guess the given dealloc method is never called (because that object is leaked) or that someone else retains the array and doesn't release it. Try putting an NSLog in dealloc to ensure that it is occurring; as a run once test you could try logging PersonListArray after releasing it — if that doesn't cause a memory exception then almost certainly someone else has retained it.
[REMOVED: my original text "Try adding an NSLog of [PersonListArray retainCount] to your dealloc to figure out which is the case."; see comment from bbum below]
The most common cause of accidental additional retains is #property/#sythesize properties that are set to retain but for which a matching release is not added to dealloc.
Somewhere else in your app, you probably call [PersonListArray objectAtIndex:n] and pass it around to various other parts of your app. One of the other parts of your app is probably leaking it.
If you're using leaks, click on the particular "type of leak", then click on the memory address, and it'll show you the alloc/free/retain/release/autorelease history of that memory address. If you enable the detail view (Cmd-E I think), you'll see stack traces for all of those as well. Look for something that's doing a retain but not a corresponding release. (It's a bit difficult when things are retained by multiple autoreleased arrays...)
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.
I've been staring at this same issue for a long time now, and would really appreciate any help or suggestions. I'm sure its something simple, but I can't seem to find it. In my app delegate I'm loading up a bunch of accessory objects (an object I created, which supports NSCopying) with the following code:
NSString *path = [[NSBundle mainBundle] pathForResource:#"Accessories" ofType:#"plist"];
NSDictionary *accDict = [[NSDictionary alloc] initWithContentsOfFile:path];
self.colors = (NSArray *) [accDict objectForKey:#"Colors"];
self.exteriorAccessories = [self loadAccessoriesForMode:EXTERIOR_MODE withDictionary:accDict];
self.interiorAccessories = [self loadAccessoriesForMode:INTERIOR_MODE withDictionary:accDict];
[accDict release];
And this is the definition for the method its calling:
-(NSArray *)loadAccessoriesForMode:(NSString *)mode withDictionary:(NSDictionary *) dictionary
{
NSMutableArray *tempValues = [[NSMutableArray alloc] init];
for (NSDictionary *value in [dictionary objectForKey:mode])
{
Accessory *accessory = [[Accessory alloc] initWithDictionary:value];
[tempValues addObject:accessory];
[accessory release];
}
NSArray *returnArray = [[NSArray alloc] initWithArray:tempValues copyItems:YES];
[tempValues release];
[returnArray autorelease];
return returnArray;
}
When I get to the release for accDict I'm getting an EXC_BAD_ACCESS exception. If I take out the release of accessory inside the loop, everything is fine - but I'm leaking Accessory objects (which seems obv. to me - if I init it and I alloc it, its my job to release it).
When I step through this in the debugger, I'm seeing the init, copy and dealloc methods all fire on my Accessory object as expected. I can also post code for the Accessory object if you think it will help, but I think the problem is somewhere in this code.
I think I've found the cause, but I'll post it here so others can possibly benefit. It didn't really have anything to do with the code I posted. Rather the problem was inside of the Accessory object. I was setting things directly instead of calling the getters through self.
So this:
value = [dict objectForKey:#"myKey"];
Instead of this:
self.value = [dict objectForKey:#"myKey"];
Somehow this was causing me to have bad side effects on the NSDictionary itself (I thought that was not mutable, but it seems I was somehow messing things up). The only way I found this was to use the very helpful advice that I found on Cocoa With Love.
When I used the Print Description option in XCode, I was able to see that the NSDictionary somehow contained AccessoryValue objects - one of my custom objects that should NOT have been there since this was just loaded from a simple plist. Print Description can be found in XCode by hovering over the object to see its details (while the process is paused in the debugger) and clicking on the little up/down arrows right next to the triangle that expands into object details. For dictionaries, this will dump their entire contents to the console.
Please prefix this with an "I know nothing about objective C but":
It looks to me like you need to release the accessory items after you have copied them into the "returnArray", or maybe not specify "copyItems".
Run Clang on your code. It's a godsend. Clang rules! It will do Static Analysis of your code and tell you what you might be leaking. Great stuff.
I was battling with the Exc_Bad_Access issue for a day and finally found the answer. The issue was when I try to access one of the objects stored in an NSDictionary, the first time was OK but the second access the object turned to be nil even though the object counts in the dictionary remains the same. This strange behavior was due to releasing the object twice. Here is an example:
NSString* nstring=[[[NSString alloc]init]autorelease]
[AnNSDictonaryInstance setObject:nstring forKey:0];
...
[nstring release];
Notice that nstring was set autorelease then release again? It won't show problem right away unit you try to read the dictionary object the second times. I hope one day Apple's development team will be able to flag this as an violation while compiling.
I hope this post will help someone out.
Wayne of Campbell