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.
Related
NSString *anError = nil;
id plist;
plist = [NSPropertyListSerialization propertyListFromData:rawCourseArray mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&anError];
if (anError != nil){
[anError release];
}
The above code causes a memory leak every time I call it. I am releasing the error but still there is a leak. I haven't seen any resolution to this issue. I posted this already and most respond that this is not a leak. But see here in the leak performance tool:
I need this fixed because eventually my app crashes. Any ideas? Many thanks
I had the same problem. Used propertyListWithData:options:format:error: with same result. Used NSDictionary initWithContentsOfFile with same result:
Leaked Object # Address Size Responsible Library Responsible Frame
NSCFNumber,19 < multiple > 304 Bytes MediaToolbox FigRemote_CreatePropertyListFromBinaryPListData
FWIW - I only have dictionaries and arrays and strings in the pList, no numbers.
The issue is not the error object (or string in your method). The issue is not plist above, since it should be autorelease. In the end, I gave up and reimplemented using JSON and:
http://stig.github.com/json-framework/api/index.html
==> no more leak.
Best,
Fred
I've had the same problem before.
Basically this is because your error variable got released without initiating it. So what you can do is try to init your NSString *error to an empty string before releasing it. Or not releasing it at all.
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.
I have the following piece of code and when I use Instruments/Object Allocations, it tells me that there is a leak there (which goes down to sqlite3MemMalloc). Is there something that I should release?
if (![managedObjectContext save:&error]) {
NSLog(#"Error while saving.");
}
The save works well and doesn't trigger an error.
The leak is most likely in one of the managed objects being saved and it just shows here. If you look at the stack in Instruments you can probably see the leaking object. Since it only shows up at save, it's probably in validation code.
Do you have any subclasses of your NSManagedObject instances?
When you set a value into your NSManagedObject instances do you then release your ownership of them? For example if you were do to the following code:
NSString *someString = [[NSString alloc] initWithString:#"Blah"];
[myManagedObject setValue:someString forKey:#"stringValue"];
You would be leaking memory because you are still owning that NSString. That is what TechZen is referring to above.
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.
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.