我的问题: - NSURLSession不会释放以前的5MB Chunk调用API内存
我在do while循环中调用API来上传500MB视频。我必须使用不同的API发送每个5MB的块,而不是在一个API中。
对于示例500MB视频并创建100个块并使用NSURLSession发送,因此调用100次但NSURLSession不会释放以前调用的5MB Chunk的API内存
(1)我创建了5MB Chunk。
(2)使用带有5MB Chunk的NSFileHandle使用OffSet
读取文件(3)更改所有块的URL并调用api(必须在不同的URL发送所有块)
我不想在NSData中转换视频(500MB)我想通过API发送块
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
//dispatch_group_t group = dispatch_group_create();
__block NSUInteger counterFailure = 0; // PSM Anks calling blob by url fails 4 time, exit for funtion
arrBlobIds = [[NSMutableArray alloc]init];
__block NSInteger intBlockIdCount = 100000; // PSM Anks blobid to assign id to every blob
__block NSUInteger offset = 0; // PSM Anks offset to start posution to read data
NSUInteger length = [[[NSFileManager defaultManager] attributesOfItemAtPath:[urlOfGallaryVideo path] error:nil] fileSize]; // PSM anks total lenght of media
NSUInteger intChunkSize = (5000 * 1024); // PSM anks chunk size
while (offset < length){
//dispatch_group_enter(group);
NSLog(@"offset 1 : %lu",(unsigned long)offset);
// PSM Anks Creat Chunk from file according to length
NSUInteger intThisChunkSize = length - offset > intChunkSize ? intChunkSize : length - offset;
//NSData* chunk = [NSData dataWithBytesNoCopy:(char *)[myBlob bytes] + offset length:intThisChunkSize freeWhenDone:NO];
__block NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:[urlOfGallaryVideo path]];
[fileHandle seekToFileOffset:offset];
__block NSData *dataChunk = [fileHandle readDataOfLength:intThisChunkSize];
// PSM Anks Convert block id in Base 64 encode
NSData *dataBlockId = [[NSString stringWithFormat:@"%ld",intBlockIdCount] dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64BlockId = [dataBlockId base64EncodedStringWithOptions:0];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@&comp=block&blockid=%@",[dictAzureSAS objectForKey:@"uri"],base64BlockId]]];
[request setHTTPMethod:@"PUT"];
[request setHTTPBody:dataChunk];
//[request setValue:[NSString stringWithFormat:@"%lu",(unsigned long)dataChunk.length] forHTTPHeaderField:@"Content-Length"]; // Do not need
//[request setValue:strVideoMIMEType forHTTPHeaderField:@"Content-Type"]; // Do not need
[request addValue:@"BlockBlob" forHTTPHeaderField:@"x-ms-blob-type"];
//NSLog(@"request : %@",request);
//NSLog(@"dataChunk.length : %lu \n url for blob %@ \n request %@",(unsigned long)dataChunk.length,[NSURL URLWithString:[NSString stringWithFormat:@"%@&comp=block&blockid=%@",[dictAzureSAS objectForKey:@"uri"],base64BlockId]],request);
NSLog(@"dataChunk.length : %lu",(unsigned long)dataChunk.length);
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.URLCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
config.timeoutIntervalForRequest = 20.0;
config.URLCredentialStorage = nil;
config.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
///NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
config = nil;
//NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *dataTaskForUpload = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"Finished with status code: %li", (long)[(NSHTTPURLResponse *)response statusCode]);
NSLog(@"response: %@", response);
NSLog(@"error: %@ %@", error,error.description);
if(data != nil) // PSM anks Check Data is nil otherwise app crashed
{
NSMutableArray *jsonList = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSLog(@"jsonList: %@", jsonList);
}
dataChunk = nil;
fileHandle = nil;
if(error == nil)
{
/*
// PSM Anks First Add Then increment
[arrBlobIds addObject:base64BlockId];
intBlockIdCount++;
offset += intThisChunkSize;
counterFailure = 0;
*/
}
else
{
/*
counterFailure++;
offset = intThisChunkSize;
if(counterFailure >= 4)
{
NSLog(@"Enter counter Failure %lu",(unsigned long)counterFailure);
counterFailure = 0;
[self stopLoader];
[CommonAlertViewMsgs cannotConnectServer:self];
return ;
}
*/
}
//dispatch_group_leave(group);
dispatch_semaphore_signal(semaphore);
[session finishTasksAndInvalidate];
}];
[dataTaskForUpload resume];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"offset 2 : %lu",(unsigned long)offset);
}
答案 0 :(得分:2)
您的问题可能是您的NSData
个对象被放入自动释放池中,在您的主dispatch_async
块完成之前,该池永远不会被耗尽。您可以通过在while循环中添加@autoreleasepool
来解决当前问题;即。
while (offset < length) @autoreleasepool {
但是,最后您的dispatch_semaphore_wait
会阻止调度队列,通常不鼓励这样做。除了将@autoreleaspool
添加到while循环之外,我建议使用调度组而不是信号量,并在末尾使用dispatch_group_notify
而不是dispatch_group_wait
。这将导致您的主dispatch_async
块完成,这将释放累积在其中的所有自动释放的对象,然后在您的所有操作完成后将调用传递给dispatch_group_notify
的块。
编辑:了解更多关于您正在尝试做的事情,这里有一个替代方案,它将一次运行一个进程,同时仍然不阻止调度队列:
(伪代码)
- (void)sendRequestWithOffset:length:otherParameters: {
send the url request {
do what you do
if newOffset < length {
[self sendRequestWithOffset:newOffset length:length otherParameters:whatever];
} else {
hooray, we're done
}
}
}
这有点像递归调用(但不是真的,因为我们不会累积堆栈帧)。基本上它是你的while循环的异步版本;你的任务一次发生一次,没有调度队列的阻塞,并且由于每个调度队列都有自己的自动释放池,你也不会积累自动释放的对象,你的内存使用应该保持合理。
答案 1 :(得分:0)
如果您想在上传过程中尽量减少内存占用,您应该:
@autoreleasepool
NSURLSession
,而不是每次在循环中重新创建一个新的NSURLSession
;和uploadTaskWithRequest:fromFile:
)而不是dataTask
。注意,使用基于文件的上传任务,您仍然可以像现在一样配置NSURLRequest
,但不要设置httpBody
,而是将其作为fromFile
参数提供上述方法。
一旦你有了这个记忆问题,你也可以采用其他方法来提高性能,但是不要超越自己。