This is the body of the selector that is specified in NSThread +detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
while (doIt)
{
if (doItForSure)
{
NSLog(#"checking");
doItForSure = NO;
(void)gettimeofday(&start, NULL);
/*
do some stuff */
// the next line prints "_NSAutoreleaseNoPool():" message to the log
CGImageRef screenImage = UIGetScreenImage();
/*
do some other stuff */
(void)gettimeofday(&end, NULL);
elapsed = ((double)(end.tv_sec) + (double)(end.tv_usec) / 1000000) - ((double)(start.tv_sec) + (double)(start.tv_usec) / 1000000);
NSLog(#"Time elapsed: %e", elapsed);
[pool drain];
}
}
[pool release];
Even with the autorelease pool present, I get this printed to the log when I call UIGetScreenImage():
2010-05-03 11:39:04.588 ProjectName[763:5903] *** _NSAutoreleaseNoPool(): Object 0x15a2e0 of class NSCFNumber autoreleased with no pool in place - just leaking
Has anyone else seen this with UIGetScreenImage() on a separate thread?
[pool drain] on iOS behaves the same as [pool release]. So after the first iteration of your while loop you end up with having no autorelease pool in place. Remove the drain and you should be fine. Not sure whether it's OK to use UIGetScreenImage() in threads other than the main thread, though.
Related
If I create a thread with a callback like..
NSAutoreleasePool* pool = [NSAutoreleasePool alloc] init];
while(1) {
//Process Stuff
}
[pool release];
I assume that anything autoreleased will never really be freed since the pool is never drained.
I could change things around to be like this:
while(1) {
NSAutoreleasePool* pool = [NSAutoreleasePool alloc] init];
//Process Stuff
[pool release];
}
But it seems a bit wasteful to alloc/delete so often. Is there a way I can set aside a block of memory and release the pool once its full?
Don't worry about it, because Autorelease is Fast. Your second option is fine. And in fact, in ARC, it will be hard to do anything besides those two options because of the new #autoreleasepool { } syntax.
If you allocate a significant* amount of autoreleased memory in each iteration of your loop, then creating and releasing a new pool for each iteration is the proper thing to do, to prevent the memory from piling up.
If you don't generate much autoreleased memory, then it wouldn't be beneficial and you will only need the outer pool.
If you allocate enough memory that a single iteration is insignificant, but there is a lot by the time you are done, then you could create and release the pool every X iterations.
#define IterationsPerPool 10
NSAutoreleasePool* pool = [NSAutoreleasePool new];
int x = 0;
while(1) {
//Process Stuff
if(++x == IterationsPerPool) {
x = 0;
[pool release];
pool = [NSAutoreleasePool new];
}
}
[pool release];
* You need to determine what significant is for yourself.
I have used the following code to create a new thread:
[NSThread detachNewThreadSelector:#selector(backgroundMethod:)
toTarget:self
withObject:paramObject];
And then in backgroundMethod I have set up a new autorelease pool as per usual:
-(void)backgroundMethod:(id)parameter
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//method stuff here...
[pool drain];
}
But somehow the autorelease pool is not working. When running the code, the output in the console is as follows:
2011-02-17 00:38:16.928 audioEngine[13670:af03] *** __NSAutoreleaseNoPool(): Object
0x4b22370 of class NSThread autoreleased with no pool in place - just leaking
I have used multiple threads in the same way before and had no similar problem - what am I doing wrong?
Any help is much appreciated! Thanks :)
EDIT: Ok this seems a bit weird - I created an autorelease pool in the method that the new thread is created from, and the problem disappeared. Any idea as to why this might be and what the right way to fix it should be? I'd rather not have a random autorelease pool in my code without knowing what it's actually doing and why the problem is gone.
EDIT2: Here's the code creating the main autorelease pool:
int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
It seems that it's complaining that the detachNewThreadSelector: call is the one that isn't being made with an autorelease pool in place, and not something within the backgroundMethod function, so that when the backgroundMethod finishes executing, the thread object is being leaked.
Check that the thread (main thread) that creates the background thread has an autorelease pool set up.
I have an iphone app project. I analysed it using instruments memory leak tool. According to instruments I have 2 leaks the Trace is as follows:
start main UIAplicationMain _run CFRunLoopInMode CFRunLoopRunSpecific PurpleEventCallback _UIAplicationHandleEvent sendEvent: handleEvent:withNewEvent:
After this trace there are two separate traces. What causes this and how can I fix it?
edit:
The leak is on the second line according to instruments
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil); //leak
[pool release];
return retVal;
Are you missing a NSAutoReleasePool for the threads?
That second method looks like some sort of callback being invoked by another component or system thread.
In the implementation, create a NSAutoReleasePool at the top and release it when the method is done:
void MyCallback {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// do stuff
[pool release];
}
It might be a false positive. UIApplicationMain probably creates a few objects that are intended to hang around for as long as the application exists and therefore never bothers to release them.
I have a background task that updates a view. That task calls -setNeedsDisplay to have the view drawn.
This works:
- (void) drawChangesTask;
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (pixels) {
drawChanges((UInt32 *) origPixels, (UInt32 *) pixels, CGBitmapContextGetBytesPerRow(ctx)/4, CGBitmapContextGetHeight(ctx), count--);
if (count < 0) {
count = 150;
}
else
[self performSelectorInBackground:#selector(drawChangesTask) withObject:nil ];
[self performSelectorOnMainThread:#selector(setNeedsDisplay) withObject:nil waitUntilDone:NO ];
}
[pool release];
}
This does not work:
- (void) drawChangesTask;
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (pixels) {
drawChanges((UInt32 *) origPixels, (UInt32 *) pixels, CGBitmapContextGetBytesPerRow(ctx)/4, CGBitmapContextGetHeight(ctx), count--);
if (count < 0) {
count = 150;
}
else
[self performSelectorInBackground:#selector(drawChangesTask) withObject:nil ];
[self setNeedsDisplay];
}
[pool release];
}
Anyone know why? When I say it doesn't work, I mean that it runs tens of iterations, sometimes I see portions of my image shifted up or down, or entirely blank, and then the deugger give me an “EXC_BAD_ACCESS” somewhere in CoreGraphics.
Also, if I don't handle the autorelease pool myself, then I get leaking error messages. Don't understand why that is either. My drawChanges() doesn't create any new objects. Here's the error:
2009-08-17 11:41:42.358 BlurApp[23974:1b30f] *** _NSAutoreleaseNoPool(): Object 0xd78270 of class NSThread autoreleased with no pool in place - just leaking
UIKit simply isn't thread-safe — you need to call methods that update UIKit controls on the main thread.
I think that this line:
[self performSelectorInBackground:#selector(drawChangesTask) withObject:nil];
Is causing trouble. Have you tried simply calling it again on the current thread? If you need the runloop to execute between the calls, use:
[self performSelector:#selector(drawChangesTask) withObject:nil afterDelay:0.0];
This will call the method on the current thread after the method you're in has finished and the runloop has gone round once.
Problem here is that UIKit is not thread safe, if you tell your UI to do something from a background thread nothign is guaranteed, what you want to do is use the performSelectorOnMainThread method to do updates t o your UI elements
Below is the runloop for my secondary NSThread* processThread
To close the thread I call
//cancel secondary thread
[processThread cancel]
//signal condition
[processCondition broadcast];
Is it then safe to then call:
[processCondition release];
[processThread release];
or do i need to be sure that the thread has finished?
Perhaps like this?
NSTimeInterval timeout = [NSDate timeIntervalSinceReferenceDate] + (1.0/15.0);
while ([processThread isExecuting] && [NSDate timeIntervalSinceReferenceDate] < timeout)
{
[NSThread sleepForTimeInterval: 1.0/1000.0 ];
}
[processCondition release];
[processThread release];
detailed code and explanation:
- (void)processLoop
{
NSAutoreleasePool * outerPool = [[NSAutoreleasePool alloc] init];
[processCondition lock];
//outer loop
//this loop runs until my application exits
while (![[NSThread currentThread] isCancelled])
{
NSAutoreleasePool *middlePool = [[NSAutoreleasePool alloc];
if(processGo)
{
//inner loop
//this loop runs typically for a few seconds
while (processGo && ![[NSThread currentThread] isCancelled])
{
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc]; init];
//within inner loop
//this takes a fraction of a second
[self doSomething];
[innerPool release];
}
[self tidyThingsUp];
}
else
{
[processCondition wait];
}
[middlePool release];
}
[processCondition unlock];
[outerPool release];
}
the combination of:
an inner while loop
NSCondition *processCondition
toggling processGo between YES and NO
allows me to stop and start the inner while loop without cancelling the thread.
if (processGo == YES)
execution enters the inner while loop.
When the main thread sets
processGo = NO
execution leaves the inner while loop and tidys up
on the next pass of the outer loop, execution hits
[processCondition wait]
and waits
if the the main thread resets
processGo == YES
and calls
[processCondition wait]
execution re-enters the inner loop
Yes, it is safe to call release against an NSThread if you are done with it. In non-GC Objective C code the idiom is that once you are done accessing an object you may release it. If anything else needs that object, including the object itself it their job to have a retain against it. In general if an object cannot be safely disposed at arbitrary times it will retain itself while it is in an unsafe state, and release itself when it can be safely disposed of.
This is how things like NSThread and NSURLConnection work (NSURLConnection actually retains its delegate and does a lot of fancy stuff to cope with the retain loop that occurs.