While it seems to not pose a problem on the simulator, using performSelectorInBackground on the device causes memory leaks. Or at least that's what Instruments indicates. Looking at the code I don't have a single clue what the cause could be.
I tried to strip the affected code to a bare minimum but still strangely Instruments keeps showing a leak every time this piece of code is executed.
Anything unusual going on here?
//In viewcontrollerA:
-(void)mainLoop
{
[self.viewControllerB performSelectorInBackground:#selector(calculateTotals) withObject:nil];
//This gives the same problem
//[NSThread detachNewThreadSelector:#selector(calculateTotals) toTarget:self.viewControllerB withObject:nil];
//UI stuff ...
}
//viewControllerB:
-(void)calculateTotals
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Heavy calculations ...
[pool release];
}
Edit:
I'm still looking into this and it seems that the leak is caused by the fact that somewhere down the stack [NSThread start] is never followed by [NSThread exit]. So it appears like there is occasionally a thread which is kept running without ever ending it.
Now my question is, is there something I could do to make end those 'hanging' threats manually?
Perhaps one of your threads is throwing an exception? Exceptions in threads don't get reported in the debug console, you have to catch the exception in the thread.
Related
I am working on someone else's code. I came across a line of code
[NSThread detachNewThreadSelector:#selector(myMethod) toTarget:self withObject:nil];
I have 2 questions to ask.
Its just calling a method. Why is NSThread used here?
While running the code, On some instances, this method doesn't get called. When I put a breakpoint inside the method, it always get called. But if I remove the breakpoint, on some instances the method doesn't get called. Is this the problem of NSThread?
Using NSThread in this way means that the method "myMethod" is being called on a background thread, concurrently with the rest of the code. It is equivalent to this, which you may also have seen:
[self performSelectorInBackground:#selector(myMethod) withObject:nil];
If the method is not getting called (or seeming to not get called), it may be down to concurrency issues, i.e. the fact that the execution order of that method and ones you call after in on the main thread is not guaranteed, so you are expecting it to be called earlier than it actually is.
If you say:
[NSThread detachNewThreadSelector:#selector(methodA) toTarget:self withObject:nil];
[self methodB];
Then methodA and methodB will be running at the same time and there is no guarantee that methodA will finish before methodB.
I always use NSThread detachNewThreadSelector in combination with an auto-release pool, like so:
-(void)myMethod {
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
// .. Do stuff in this thread
[pool release];
};
If you want to "simply" perform a selector, do it like this:
[self performSelector:#selector(myMethod)];
I am detaching a new thread
[NSThread detachNewThreadSelector:#selector(loadAvatar) toTarget:self withObject:nil];
I am getting an EXC_BAD_ACCESS on
STObject* st = [cellitem get:#"stobject"];
In my following method
-(void)loadAvatar
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
STObject* st = [cellitem get:#"stobject"];
//do stuff...
[pool release];
}
I have tried retaining st but no luck. When I run this code without detaching a new thread I have no problems. I am not really sure what I am missing.
UPDATE
cellitem is a subclass of NSObject that contains some properties such as a dictionary and strings.
The get method basically returns a string from a dictionary
Retaining st is not going to do you much good, since the EXC_BAD_ACCESS error originates from before the assignment takes place. The problem lies either with accessing cellItem or in your get method. Either way you are likely trying to access an object that has already been released. Try running Instruments with zombie detection enabled.
Not exactly sure why this solution works, but I told my thread to sleep for 0.1 seconds and it seems to solve all of the problems.
[NSThread detachNewThreadSelector:#selector(loadAvatar) toTarget:self withObject:nil];
[NSThread sleepForTimeInterval:0.1];
Does anyone know why this is so? I am guessing sleeping prevents some object from being released too early? Could be a hacky fix.
I've been experiencing memory problems (the app will run for a couple of iterations, then receive low memory warning and finally be terminated) while working with NSInvocationOperation in a method called repeatedly by a NSTimer.
The method will be called every 1/4 of a second and I've narrowed down the source of the problem to the following test lines:
-(void)methodCalledByTimer {
NSInvocationOperation *o = [NSInvocationOperation alloc];
[o release];
}
Uncommenting these two lines (to produce an empty method) will prevent the memory problems from arising. Once they are in, memory usage will increase quite fast and finally the app will be terminated.
Can anybody explain what I'm doing wrong here? Do I have to do anything else to make sure, that the NSInvocationOperation object will be properly released?
Thank you very much in avance for your help.
Kind regards,
Michael.
A possible solution might be to just store your NSInvocationOperation somewhere else instead of creating and releasing one each time methodCalledByTimer is called.
I was having problems with NSCalendar where I would create and release one thousands of times to be used for some date work, but I then just created one calendar attached to the appDelegate and accessed that every time. Fixed a ton of memory leaks, and it's probably better than creating a new object every single time.
I believe the problem lies in how you allocate without initializing. The first of the buggy lines should read:
NSInvocationOperation *o = [[NSInvocationOperation alloc] initWithTarget:yourTarget selector:#selector(yourSelector) object:yourObjectOrNil];
Regarding mjdth's answer, I believe you should not attempt to reuse an invocation operation. From the documentation of NSOperation (the superclass of NSInvoationOperation):
"An operation object is a single-shot object—that is, it executes its task once and cannot be used to execute it again."
Furthermore, no Objective-C object should ever be initialized twice.
I want my application to never just crash stupidly. I know that code quality is the root solution for this. But I still need an application to never crash when some unexpected bug happens. Here is code I want to try.
-(void)testException
{
#try
{
NSString* str;
[str release];
}
#catch(NSException* ex)
{
NSLog(#"Bug captured");
}
}
I know this one does not work. Because release never raise an exception. Here are my questions:
How to reach this kind of objective, bug will be captured, no crash?
How do I know which system library will raise exception and so I can write some code and know it works?
Here's what I have read
a. Exception Programming Topics for
Cocoa
b. Error Handling Programming
Guide For Cocoa
I come from an experienced Microsoft programmer background in which catch exception or unexpected exception always prevent my program from crashing in a very bad environment.
How did you guys/gals (Mac genius programmers) make crash free programs happened? Share your experience.
Objective-C is an unmanaged runtime; the code that you compile runs directly on the CPU rather than in a virtual machine. That means you don't have the supervisory layer that can trap every possible failure mode the way you do when running in the .NET VM or the JVM. The long and short of it is that the only way you're going to be completely sure a program can't crash is to code very carefully and test very thoroughly. And even then, you're not sure, you just think you are.
The latest version of Xcode integrates the Clang static analyzer ('Build and Analyze' in the Build menu) that can identity some classes of potential bugs -- I'm fairly sure it would flag your example above, for instance). But there is no magic bullet here; the only solution is hard work.
Test Test Test Test Test
You can spend all day writing exception-handling code for possible exceptions (that in practice will never occur), or you can create thorough test suites and only write exception handlers for situations that occur in practice.
This is why I almost never write exception handlers. If you fix the underlying issues that are causing the exception, then you don't need to handle anything.
Of course, there are situations where can't ensure that a method call won't cause an exception and you need to be prepared, but wrapping everything in #try/#catch blocks is definitely not the solution.
One issue you are having is that str is never initialized which means that str may be pointing to nil (but this is not guaranteed). It is definitely pointing to junk.
If you step through your code, I can almost guarantee that your release is being called on nil, which in Objective-C is completely valid.
Try doing this:
NSString *str = [[NSString alloc] initWithString:#"a string"];
[str release];
[str release];
Calling release does not deallocate an object, it simply decrements the retain count by 1. When an objects retain count is 0,
[self dealloc];
is called automatically.
If the above code does not throw an exception immediately, it may be because the actual deallocation message is delayed at some future point (I'm not sure exactly when dealloc is called after the retain count reaches 0. I think it is called immediately and on the same thread, but some other Cocoa ninja will know for sure).
What you can do is add a category to NSObject and implement the dealloc and release methods and try to catch you're exception in there.
- (void)dealloc{
#try
{
[super dealloc];
}
#catch(NSException* ex)
{
NSLog(#"Bug captured");
}
}
- (void)release{
#try
{
[super release];
}
#catch(NSException* ex)
{
NSLog(#"Bug captured");
}
}
The added bonus is that this code will be valid for every object in your app since it is a category on NSObject.
To be complete though, if you just practice them memory management rules, you will be fine.
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.