performSelectorInBackground makes memory leak - ios

This gives me memory leak, even thought I call create and release pool in the selector function.
[read_qr performSelectorInBackground:#selector(newThreadWrapper) withObject:nil];
class read_qr:
- (void) newThreadWrapper {
reading = YES;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self another_function:arg];
[pool release];
reading = NO;
}
There is no leak if I call the same function in the main thread without performSelectorInBackground.
Any tips are appreciated.
Thank you.

Related

iOS memory leak in thread

After running my thread for a while, Instruments shows that __NSDate has steadily incementing its # living value.
My conclusion is that this tread does not dealocate objects. This line, however, causes compilation error NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
How can I force this thread to retain all its objects or how shall I create a proper thread with working ARC.
- (void) start {
NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:#selector(myThreadMainRoutine)
object:nil];
[myThread start]; // Actually create the thread
}
- (void)myThreadMainRoutine {
// stuff inits here ...
// Do thread work here.
while (_live) {
// do some stuff ...
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
[NSThread sleepForTimeInterval:0.05f];
}
// clean stuff here ...
}
The autoreleased objects are probably the reason for the increasing memory usage,
but you cannot use NSAutoreleasePool with ARC. Replace
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// ...
[pool drain];
with
#autoreleasepool {
// ...
}
Update: You actually need two autorelease pools in your case. First of all, the
Threading Programming Guide states:
If your application uses the managed memory model, creating an
autorelease pool should be the first thing you do in your thread entry
routine. Similarly, destroying this autorelease pool should be the
last thing you do in your thread. This pool ensures that autoreleased
objects are caught, although it does not release them until the thread
itself exits.
And the last sentence gives the clue why you need another autorelease pool: Otherwise
all autoreleased objects created in the long-running loop would only be released when
the thread exits. So you have
- (void)myThreadMainRoutine {
#autoreleasepool {
// stuff inits here ...
while (_live) {
#autoreleasepool {
// do some stuff ...
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
[NSThread sleepForTimeInterval:0.05f];
}
}
// clean stuff here ...
}
}
- (void)myThreadMainRoutine {
#autoreleasepool {
// stuff inits here ...
// Do thread work here.
while (_live) {
// do some stuff ...
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
[NSThread sleepForTimeInterval:0.05f];
}
// clean stuff here ...
}
}

Finding the cause of memory leak in Instruments

I have run the leaks in Instruments and it is showing me a memory leak with a 100% value. I am able to see the line of code that is causing the problem. But not really sure what the error is..
- (void) listAllBooks {
if (marrListFromDB != nil) {
[marrListFromDB removeAllObjects];
marrListFromDB = nil;
}
marrListFromDB = [[NSMutableArray alloc] init];
ServerCommunicationAPI *servApi = [[ServerCommunicationAPI alloc] init];
servApi.delegate = self;
NSURL *url = [NSURL URLWithString:kLISTCONTENTS];
[servApi listBooksWithDeviceID:singleton.g_strdevID deviceKey:singleton.g_strdevID andSessionString:singleton.g_strSessionID sessionKey:#"sessionKey" URL:url andRequestMethod:#"POST"];
}
The line of error is the last one. Not sure why it is causing a memory leak... Need some guidance..
It is hard to tell from the information provided, but maybe the delegate property of ServerCommunicationAPI is declared as (strong)? In this case servApi could never be released, because it keeps a strong reference to itself (retain cycle).
I suggest that you check in instruments which kind of object leaks, this would make the answer much easier.
Try out this. May it resolve your memory leak problem.
- (void) listAllBooks {
if (marrListFromDB != nil) {
[marrListFromDB removeAllObjects];
marrListFromDB = nil;
}
ServerCommunicationAPI *servApi ;
marrListFromDB = [[NSMutableArray alloc] init];
if(servApi == nil){
ServerCommunicationAPI *servApi = [[ServerCommunicationAPI alloc] init];
}//Every time it going to alloc. It's strong object may be due do this memory leak happens.
servApi.delegate = self;
NSURL *url = [NSURL URLWithString:kLISTCONTENTS];
[servApi listBooksWithDeviceID:singleton.g_strdevID deviceKey:singleton.g_strdevID andSessionString:singleton.g_strSessionID sessionKey:#"sessionKey" URL:url andRequestMethod:#"POST"];
}
Just another idea: Maybe you execute your code in a separate thread for which no autorelease pool has been set up? In this case the message sent to servApi could create autorelease objects that cannot be released later since no autorelease pool exists.
So, if your code is not executed in the main thread, please check if an autorelease pool has been set up using a #autoreleasepool {...} block for your thread.

SKPSMTPMessage freezing my program

Recently i decided to use the SKPSMTPMessage Class for transferring images to a server.
I subclassed the NSOperation Class, implemented the funktionality and added it to a NSOperationQueue, because i don't want my app to be blocked and the user can't do anything while its uploading the image. This usually occur, when i use the GSM network and it lasts a long time, until it the image is being sent. (By the way, i don't want to do any compressions on the image)
- (void)main {
SKPSMTPMessage *testMsg = [[SKPSMTPMessage alloc] init];
testMsg.fromEmail = [[_from copy] autorelease];
testMsg.toEmail = [[_to copy] autorelease];
testMsg.relayHost = [[_relayHost copy] autorelease];
testMsg.subject = [[_subject copy] autorelease];
testMsg.delegate = self.delegate;
testMsg.parts = [[_mailParts copy] autorelease];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[testMsg performSelectorOnMainThread:#selector(send) withObject:nil waitUntilDone:NO];}
To be clear, i release the obect in the delegate i assign to the SKPSMTMessage instance. So it's not causing any leaks.
The Problem is, that i have to use performSelectorOnMainThread: because otherwise its not working. It stops right after
C: Attempting to connect to server at: mail.example.com:25
I've found this post here, that describes pretty much the same problem i'm currently facing, but i can't figure out, how its going to work.
The solution they described was, that they used to run the program in another thread.
[NSThread detachNewThreadSelector:#selector(launchJobWithJob:) toTarget:self withObject:jobDescription];
[[NSRunLoop currentRunLoop] run];
But when i do this without using the NSOperation subclass, it causes me this error:
_NSAutoreleaseNoPool(): Object 0x18a140 of class NSCFString autoreleased with no pool in place - just leaking
but still not working. It again only prints this "C: Attempting to connect to server at: mail.example.com:25".
Can anyone please help?
EDIT
In the Subclass NSOperation I now use instead of
[testMsg performSelectorOnMainThread:#selector(send) withObject:nil waitUntilDone:NO];
that code.
[testMsg send];
[[NSRunLoop currentRunLoop] run];
It helps me getting across the freezing problem, but the reliability of the message being sent is not given.
It works now! I use following code in the NSOperation Subclass (btw: My subclasses name is SMTPSendOperation):
- (void)main
{
SKPSMTPMessage *testMsg = [[SKPSMTPMessage alloc] init];
testMsg.fromEmail = [[_from copy] autorelease];
testMsg.toEmail = [[_to copy] autorelease];
testMsg.relayHost = [[_relayHost copy] autorelease];
testMsg.subject = [[_subject copy] autorelease];
testMsg.delegate = self.delegate;
testMsg.parts = [[_mailParts copy] autorelease];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//[testMsg performSelectorOnMainThread:#selector(send) withObject:nil waitUntilDone:NO];
//[NSThread detachNewThreadSelector:#selector(send) toTarget:<#(id)#> withObject:<#(id)#>]
[testMsg send];
[[NSRunLoop currentRunLoop] run];
}
Anyhow, i'll have to tell the user to be patient until the mail is being sent successfully or failed. If anyone has any idea, how i can use the thread to be run more efficient, i'll really appreciate that!

Runtime error: __NSAutoreleaseNoPool(): ...autoreleased with no pool in place - just leaking

I am getting a list of errors like the following error when I compile my project for iOS.
2011-08-25 12:32:44.016 rtsp[55457:6003]
*** __NSAutoreleaseNoPool(): Object 0x64095a0 of class __NSArrayM
autoreleased with no pool in place - just leaking
It appears because of the following function
- (void) start {
//Existing code
session = [[RTSPClientSession alloc] initWithURL:
[NSURL URLWithString:
#"rtsp://video3.americafree.tv/AFTVComedyH2641000.sdp"]];
[session setup];
NSLog(#"getSDP: --> %#",[ session getSDP ]);
NSArray *array = [session getSubsessions];
for (int i=0; i < [array count]; i++) {
RTSPSubsession *subsession = [array objectAtIndex:i];
[session setupSubsession:subsession clientPortNum:0 ];
subsession.delegate=self;
[subsession increaseReceiveBufferTo:2000000];
NSLog(#"%#", [subsession getProtocolName]);
NSLog(#"%#", [subsession getCodecName]);
NSLog(#"%#", [subsession getMediumName]);
NSLog(#"%d", [subsession getSDP_VideoHeight]);
NSLog(#"%d", [subsession getServerPortNum]);
}
[session play];
NSLog(#"error: --> %#",[session getLastErrorString]);
[session runEventLoop:rawsdp];
}
When I add and NSAutoreleasePool to my function
- (void) start {
NSAutoReleasePool *pool=[[NSAutoReleasePool alloc] init];
session = [[RTSPClientSession alloc] initWithURL:[NSURL ...
...
[pool drain];
}
The error is gone but I don't get any output from my function. Is adding NSAutoreleasePool the right solution?
You get the message on the console because you are running the start method on a background thread and have not placed an Autorelease pool in place that will take care of reclaiming objects once they have been released (release count == 0 ),this doesnt happen in the main thread because the main thread already has a pool in place, for background threads u spawn you are responsible to set up the autorelease pool... your solution is the right solution to the problem.. so here is an example of when to and where to use autorelease pool
One way to spawn something to execute in the background is by calling performSelectorInBackground method of NSObject which i assume you are doing
[myObject performSelectorInBackground:(#selector(myBackgroundMethod:) withObject:nil];
Now this method is going to execute on a background thread and you need to place an Autorelease pool in place in order for it not to leak, like so
-(void)myBackgroundMethod:(id)sender
{
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
//do stuff
[pool release];
}
hope that clears it up
Daniel

Equivalent of GCD serial dispatch queue in iOS 3.x

Apple's Grand Central Dispatch (GCD) is great, but only works on iOS 4.0 or greater. Apple's documentation says, "[A] serialized operation queue does not offer quite the same behavior as a serial dispatch queue in Grand Central Dispatch does" (because the queue is not FIFO, but order is determined by dependencies and priorities).
What is the right way to achieve the same effect as GCD's serial dispatch queues while supporting OS versions before GCD was released? Or put another way, what is the recommended way to handle simple background processing (doing web service requests, etc.) in iOS apps that want to support versions less than 4.0?
How about this PseudoSerialQueue? It is a minimal implementation like the Dispatch Serial Queue.
#import <Foundation/Foundation.h>
#interface PseudoTask : NSObject
{
id target_;
SEL selector_;
id queue_;
}
#property (nonatomic, readonly) id target;
- (id)initWithTarget:(id)target selector:(SEL)selector queue:(id)queue;
- (void)exec;
#end
#implementation PseudoTask
#synthesize target=target_;
- (id)initWithTarget:(id)target selector:(SEL)selector queue:(id)queue;
{
self = [super init];
if (self) {
target_ = [target retain];
selector_ = selector;
queue_ = [queue retain];
}
return self;
}
- (void)exec
{
[target_ performSelector:selector_];
}
- (void)dealloc
{
[target_ release];
[queue_ release];
}
#end
#interface PseudoSerialQueue : NSObject
{
NSCondition *condition_;
NSMutableArray *array_;
NSThread *thread_;
}
- (void)addTask:(id)target selector:(SEL)selector;
#end
#implementation PseudoSerialQueue
- (id)init
{
self = [super init];
if (self) {
array_ = [[NSMutableArray alloc] init];
condition_ = [[NSCondition alloc] init];
thread_ = [[NSThread alloc]
initWithTarget:self selector:#selector(execQueue) object:nil];
[thread_ start];
}
return self;
}
- (void)addTask:(id)target selector:(SEL)selector
{
[condition_ lock];
PseudoTask *task = [[PseudoTask alloc]
initWithTarget:target selector:selector queue:self];
[array_ addObject:task];
[condition_ signal];
[condition_ unlock];
}
- (void)quit
{
[self addTask:nil selector:nil];
}
- (void)execQueue
{
for (;;) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[condition_ lock];
while (array_.count == 0)
[condition_ wait];
PseudoTask *task = [array_ objectAtIndex:0];
[array_ removeObjectAtIndex:0];
[condition_ unlock];
if (!task.target) {
[pool drain];
break;
}
[task exec];
[task release];
[pool drain];
}
}
- (void)dealloc
{
[array_ release];
[condition_ release];
}
#end
How to use:
PseudoSerialQueue *q = [[[PseudoSerialQueue alloc] init] autorelease];
[q addTask:self selector:#selector(test0)];
[q addTask:self selector:#selector(test1)];
[q addTask:self selector:#selector(test2)];
[q quit];
Seems like people are going to a lot of effort to rewrite NSRunloop. Per the NSRunloop documentation:
Your application cannot either create
or explicitly manage NSRunLoop
objects. Each NSThread object,
including the application’s main
thread, has an NSRunLoop object
automatically created for it as
needed.
So surely the trivial answer would be, to create a usable queue:
- (void)startRunLoop:(id)someObject
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[NSRunLoop currentRunLoop] run];
[pool release];
}
...
NSThread *serialDispatchThread = [[NSThread alloc]
initWithTarget:self
selector:#selector(startRunLoop:)
object:nil];
[serialDispatchThread start];
To add a task to the queue:
[object
performSelector:#selector(whatever:)
onThread:serialDispatchThread
withObject:someArgument
waitUntilDone:NO];
Per the Threading Programming Guide section on Run Loops:
Cocoa defines a custom input source
that allows you to perform a selector
on any thread. ... perform selector requests are
serialized on the target thread,
alleviating many of the
synchronization problems that might
occur with multiple methods being run
on one thread.
So you've got an explicitly serial queue. Of course, mine isn't fantastically written because I've told the run loop to run forever, and you may prefer one you can terminate later, but those are easy modifications to make.
you can simulate it using NSOperationQueue, then just set the task count to one.
EDIT
-- oops, should have read more carefully. the fifo solution follows:
i can't think of a way that the majority of ios devs would use in your situation.
i'm not afraid of writing threaded programs, so here is one solution:
create a fifo worker queue that:
supports locking
holds one NSOperationQueue
holds an NSOperation subclass, designed to pull workers from the fifo queue in its implementation of main. only one may exist at a time.
holds an NSArray of workers to be run (defining a worker is up to you - is it an NSInvocation, class, operation, ...)
the NSOperation subclass pulls the workers from the fifo worker queue until the fifo worker queue is exhausted.
when the fifo work queue has workers and no active child operation, it creates a child operation, adds it to its operation queue.
there are a few pitfalls if you aren't comfortable writing threaded programs -- for this reason, this solution is not ideal for everybody, but this solution would not take very long to write if you are already comfortable using all the technologies required.
good luck
There are things NSOperationQueue documentation writer forgot to mention, making such implementation seem trivial when in fact it's not.
Setting the maximum concurrent operation count to 1 is guaranteed to be serial only
if NSOperations are added to the queue from same thread.
I'm using another option because it just works.
Add NSOperations from different threads but use NSCondition to manage queuing.
startOperations can (and should, you don't want to block main thread with locks) be called with performSelectorOnBackgroundThread...
startOperations method represents single job that consists of one or more NSOperations.
- (void)startOperations
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[AppDelegate condition] lock];
while (![[[AppDelegate queue] operations] count] <= 0)
{
[[AppDelegate condition] wait];
}
NSOperation *newOperation = [alloc, init]....;
[[AppDelegate queue] addOperation:newOperation];
[[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don't forget this!
NSOperation *newOperation1 = [alloc, init]....;
[[AppDelegate queue] addOperation:newOperation1];
[[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don't forget this!
NSOperation *newOperation2 = [alloc, init]....;
[[AppDelegate queue] addOperation:newOperation2];
[[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don't forget this!
// Add whatever number operations you need for this single job
[[AppDelegate queue] signal];
[[AppDelegate queue] unlock];
[NotifyDelegate orWhatever]
[pool drain];
}
That's it!
If the processing is in the background anyway, do you really need it to be strictly in-order? If you do, you can achieve the same effect simply by setting up your dependencies so 1 depends on 0, 2 on 1, 3 on 2, etc. The operation queue is then forced to handle them in order. Set the maximum concurrent operation count to 1, and the queue is also guaranteed to be serial.

Resources