nstask waitForDataInBackgroundAndNotify taking huge memory

Hi All,


I am using NSTask to execute an external binary and I have connected NSPipe to listen for the data. But the memory usage of my app is raising hugely at prolonged use, even before my binary execution is finished.


How to reduce this and is there any alternate other than adding observers to listen for data from task.


Thanks,

Arul

Accepted Reply

here is the code snippet


NSTask *fileCountTask = [NSTask new];

[fileCountTask setLaunchPath:launchPath];

[fileCountTask setArguments:@[@"-c", command]];


NSPipe *outputPipe = [NSPipe pipe];

[fileCountTask setStandardInput:[NSPipe pipe]];

[fileCountTask setStandardOutput:outputPipe];

[fileCountTask launch];


NSFileHandle *objectHandle=[outputPipe fileHandleForReading];

[objectHandle waitForDataInBackgroundAndNotify];


if (!taskObserverArray)

{

taskObserverArray = [NSMutableArray array];

}

dispatch_semaphore_t sema = dispatch_semaphore_create(0);

id taskProgressObserver = [[NSNotificationCenter defaultCenter]

addObserverForName:NSFileHandleDataAvailableNotification

object:objectHandle

queue:[NSOperationQueue mainQueue]

usingBlock:^(NSNotification *note)

{

dispatch_semaphore_signal(sema);

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

if (taskBlock)

{

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

taskBlock(note);

});

}

}];


id taskTerminationObserver = [[NSNotificationCenter defaultCenter]

addObserverForName:NSTaskDidTerminateNotification

object:fileCountTask

queue:[NSOperationQueue mainQueue]

usingBlock:^(NSNotification *note)

{

dispatch_semaphore_signal(sema);

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

if (taskTerminationBlock)

{

taskTerminationBlock(note);

}

}];


Here is the code inside my block


@autoreleasepool {

NSData *outData = [note.object availableData];

NSString *outStr = @"";

if (outData.length)

{

outStr = [[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding];

}

if (outStr && outStr.length)

{

NSMutableArray *tempArray = [[NSMutableArray alloc] initWithArray:[outStr componentsSeparatedByString:@"\r"]];

if ([[tempArray objectAtIndex:0] length] <= 0) {

[tempArray removeObjectAtIndex:0];

}

if([[tempArray objectAtIndex:[tempArray count]-1]length]<=0)

{

[tempArray removeLastObject];

}

NSInteger arrayCount = [tempArray count];

NSInteger finalValue;

if (arrayCount >=2) {

NSInteger lastBeforeValue=[[tempArray objectAtIndex:arrayCount-2]integerValue];

NSInteger lastValue=[[tempArray objectAtIndex:arrayCount-1]integerValue];

if(lastValue>lastBeforeValue)

finalValue=lastValue;

else

finalValue=lastBeforeValue;

}else{

finalValue = [[tempArray firstObject]integerValue];

}

outStr = nil;

tempArray = nil;

dispatch_async(dispatch_get_main_queue(), ^

{

[_delegate noofFilesToBeScanned:finalValue];

_totalNumberOfFilesToScan=finalValue;

_client.totalFilesToScanCount=finalValue;

[note.object waitForDataInBackgroundAndNotify];

});

}

}

Replies

I can’t think of any obvious reason why

-waitForDataInBackgroundAndNotify
would consume vast quantities of memory. If you run the Allocations instrument on the program while it’s doing this, what types of objects are being allocated?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Even after commenting out all the code I do in the data available call back method, the memory shoots up.

Actually i am running 2 tasks and add a view controller as observer for both the tasks. Both the tasks run concurrently.

Even after commenting out all the code I do in the data available call back method, the memory shoots up.

That’s interesting, but I’m still interested in hearing what type of objects are being allocated here.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

here is the code snippet


NSTask *fileCountTask = [NSTask new];

[fileCountTask setLaunchPath:launchPath];

[fileCountTask setArguments:@[@"-c", command]];


NSPipe *outputPipe = [NSPipe pipe];

[fileCountTask setStandardInput:[NSPipe pipe]];

[fileCountTask setStandardOutput:outputPipe];

[fileCountTask launch];


NSFileHandle *objectHandle=[outputPipe fileHandleForReading];

[objectHandle waitForDataInBackgroundAndNotify];


if (!taskObserverArray)

{

taskObserverArray = [NSMutableArray array];

}

dispatch_semaphore_t sema = dispatch_semaphore_create(0);

id taskProgressObserver = [[NSNotificationCenter defaultCenter]

addObserverForName:NSFileHandleDataAvailableNotification

object:objectHandle

queue:[NSOperationQueue mainQueue]

usingBlock:^(NSNotification *note)

{

dispatch_semaphore_signal(sema);

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

if (taskBlock)

{

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

taskBlock(note);

});

}

}];


id taskTerminationObserver = [[NSNotificationCenter defaultCenter]

addObserverForName:NSTaskDidTerminateNotification

object:fileCountTask

queue:[NSOperationQueue mainQueue]

usingBlock:^(NSNotification *note)

{

dispatch_semaphore_signal(sema);

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

if (taskTerminationBlock)

{

taskTerminationBlock(note);

}

}];


Here is the code inside my block


@autoreleasepool {

NSData *outData = [note.object availableData];

NSString *outStr = @"";

if (outData.length)

{

outStr = [[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding];

}

if (outStr && outStr.length)

{

NSMutableArray *tempArray = [[NSMutableArray alloc] initWithArray:[outStr componentsSeparatedByString:@"\r"]];

if ([[tempArray objectAtIndex:0] length] <= 0) {

[tempArray removeObjectAtIndex:0];

}

if([[tempArray objectAtIndex:[tempArray count]-1]length]<=0)

{

[tempArray removeLastObject];

}

NSInteger arrayCount = [tempArray count];

NSInteger finalValue;

if (arrayCount >=2) {

NSInteger lastBeforeValue=[[tempArray objectAtIndex:arrayCount-2]integerValue];

NSInteger lastValue=[[tempArray objectAtIndex:arrayCount-1]integerValue];

if(lastValue>lastBeforeValue)

finalValue=lastValue;

else

finalValue=lastBeforeValue;

}else{

finalValue = [[tempArray firstObject]integerValue];

}

outStr = nil;

tempArray = nil;

dispatch_async(dispatch_get_main_queue(), ^

{

[_delegate noofFilesToBeScanned:finalValue];

_totalNumberOfFilesToScan=finalValue;

_client.totalFilesToScanCount=finalValue;

[note.object waitForDataInBackgroundAndNotify];

});

}

}