我的问题:- NSURLSession 不会释放先前调用的 5MB block 的 API 内存
我在 do while 循环中调用 API 来上传 500MB 视频。我必须使用不同的 API(而不是在一个 API 中)发送每 5MB block 。
例如,500MB 视频并创建 100 个 block 并使用 NSURLSession 发送,因此调用 100 次,但 NSURLSession 不会释放先前调用的 5MB block 的 API 内存
(1) 我创建了 5MB block 。
(2) 使用 NSFileHandle 读取文件并使用 OffSet 读取 5MB block
(3) 更改所有 block 的 URL 并调用 api(需要在不同的 URL 发送所有 block )
我不想在 NSData 中转换视频(500MB),我想通过 API 发送 block
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);
}
最佳答案
您的问题可能是您的NSData
对象被放入自动释放池中,直到您的 main dispatch_async
之后它才会被耗尽。 block 完成。您可以通过添加 @autoreleasepool
来解决眼前的问题。到你的 while 循环;即
while (offset < length) @autoreleasepool {
但是,您的dispatch_semaphore_wait
最后会阻塞调度队列,这通常是不鼓励的。我建议除了添加 @autoreleaspool
之外,到 while 循环,使用调度组而不是信号量,并使用 dispatch_group_notify
最后而不是 dispatch_group_wait
。这将导致您的主要 dispatch_async
block 完成,这将释放其中积累的所有自动释放的对象,然后是您传递给 dispatch_group_notify
的 block 所有操作完成后将被调用。
编辑:更多地了解您想要做什么,这里有一种替代方案,它将一次运行一个进程,同时仍然不会阻塞调度队列:
(伪代码)
- (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 循环的异步版本;您的任务一次只发生一个,不会阻塞调度队列,并且由于每个调度队列都有自己的自动释放池,因此您也不会积累自动释放的对象,并且您的内存使用量应该保持合理。
关于objective-c - 可能是 NSURLSession 或 NSMutableURLRequest 没有通过循环释放内存调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47078719/