简体   繁体   English

NSThread导致iPhone中的内存泄漏

[英]NSThread Causing memory Leaks in iPhone

I am uploading images chunk wise, in a background thread, each chunk will be size of 512kb,to the best of my knowledge,i have taken care of memory leaks using release,nsautoreleasepool. 我在后台线程中明智地上传图像,每个块的大小为512kb,据我所知,我已经使用release,nsautoreleasepool来处理内存泄漏问题。 Below is the code for uploading images chunkwise. 以下是分块上传图像的代码。

- (void)FetchDataFromDB : (NSNumber *) isOffline
{
 @autoreleasepool {
    @try {
    NSLog(@"FetchDatafromDB");
    isThreadStarted = YES;

    VYukaDBFunctions *vdb = [VYukaDBFunctions getInstance];

    NSMutableArray *fileNames = [vdb GetFileNames:[isOffline integerValue]];
    for(int j=0 ; j<[fileNames count] ; j++)
    {

        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSString * filename = fileNames [j] ;
        int _outgoingMsgId = [[vdb SelectMsgId:filename] intValue];
        int  _totalchunk =[[vdb SelectTotalChunk:filename]intValue];
        int currentChunk = [vdb GetCurrentChunk:filename];
    for( int i=currentChunk ; i <= _totalchunk ; i++)
    {

        NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];

        NSString *AsyncRequest = [[NSString alloc] init];
        AsyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];

        if(![AsyncRequest isEqual:@""])
        {

        BOOL status = [self UploadChunkWise :AsyncRequest : 1 : i : vdb : filename : _outgoingMsgId];
      // AsyncRequest = NULL;
     //  [AsyncRequest release];
        if(status){
            if(i==_totalchunk)
            {
                NSLog(@"Deleting from medialist , FileName :%@", filename);
                [vdb DeleteFromMediaList : filename];

            }
        }
        else{

            [vdb DeleteFromMediaList : filename];
            break;
        }
        }

        [innerPool drain];
    }

        [pool drain];
    }

    [fileNames removeAllObjects];

   // [fileNames release];

    //recurssive call to check any pending uploads..
    if([[vdb GetFileNames:[isOffline integerValue]] count] > 0)
    {
        NSLog(@"Calling Recursively..");
        [self FetchDataFromDB:[isOffline integerValue]];
    }

    }
    @catch (NSException *exception) {

        NSLog(@"Exception caught on Uploading from FetchDataFromDB:%@", exception);

    }
    @finally {

    }
}

 NSLog(@"thread quit ");
 isThreadStarted = NO;
[NSThread exit];

}

-(BOOL) UploadChunkWise :(NSString *) AsyncRequest : (int) count : (int)currentChunk : (VYukaDBFunctions * ) vdb : (NSString *) currentFileName : (int) outgoingMsgId
{

NSHTTPURLResponse *response ;
NSError *error;
//Yes, http
NSMutableURLRequest *httpRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL     URLWithString:@"Url goes here"]];
NSData* data = [AsyncRequest dataUsingEncoding:NSUTF8StringEncoding];

[httpRequest setHTTPMethod:@"POST"];
[httpRequest setHTTPBody:data];

[httpRequest setValue:@"application/xml" forHTTPHeaderField:@"Content-Type"];
NSData *returnedData = [NSURLConnection sendSynchronousRequest: httpRequest returningResponse:&response error:&error] ;
NSString *result= [[NSString alloc] initWithData:returnedData encoding:NSASCIIStringEncoding];
[httpRequest release];

returnedData= NULL;
[returnedData release];
data = NULL;
[data release];

if ([result rangeOfString:@"success"].location != NSNotFound )
{
    NSLog(@" success");
    [vdb DeleteCurrentChunkFromOutgoingTable:currentChunk : outgoingMsgId];
    [result release];
    return YES ;

}
else if ([result rangeOfString:@"fail"].location != NSNotFound )
{
    [result release];
    if (count < 3) {

        return  [self UploadChunkWise :AsyncRequest : count+1 : currentChunk: vdb : currentFileName : outgoingMsgId ];
    }
    else
    {
        NSLog(@" failed");
        [vdb DeleteAllCurrentFileChunksFromOutgoingTable:currentFileName];
        return NO ;
    }

}

return NO;

}

I am starting thread as below 我正在如下启动线程

 [NSThread detachNewThreadSelector:@selector(FetchDataFromDB:) toTarget:self withObject:[NSNumber numberWithInt:0]];

The problem is after uploading 9 to 12 chunks, i am getting memory error. 问题是上传9到12个块后,出现内存错误。 i am getting 4 to 5 times memory warning and after that app crashes.in console i am getting memory warning first at app delegate class, followed by 4 classes which are extending UIViewController. 我收到4到5次内存警告,然后该应用程序崩溃。在控制台中,我首先在应用程序委托类上获取内存警告,然后是4个扩展UIViewController的类。 why i am getting warning at app delegate, and other classes which is of type UIViewController.Why i have to release object of other class if the separate thread is giving me memory error? 为什么我在应用程序委托和其他类型为UIViewController的类上收到警告。如果单独的线程给我内存错误,为什么我必须释放其他类的对象? what i am doing wrong here? 我在这里做错了什么? I cannot use ARC, as i have integrated this with old code, which is not using ARC, i tried enabling ARC class wise, but it dint work. 我无法使用ARC,因为我已将其与不使用ARC的旧代码集成在一起,因此我尝试了明智地启用ARC类,但是这样做并不起作用。 Can any one help me to find out if there is any memory leaks in this code. 谁能帮助我找出这段代码中是否有内存泄漏。 Suggestions are welcomed and appreciated.Thanks in advance.. 欢迎提出建议并表示赞赏。

Two things- first, I see this: 两件事-首先,我看到了这一点:

NSString *AsyncRequest = [[NSString alloc] init];
AsyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];

This should be consolidated to this: 这应该合并为:

NSString *asyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];

You instead are creating a new instance, then immediately either generating or referencing another instance. 相反,您正在创建一个新实例,然后立即生成或引用另一个实例。

Second: 第二:

Your code is very hard to read and doesn't follow the Objective-C smalltalk conventions. 您的代码很难阅读,并且不遵循Objective-C smalltalk约定。

Variable names should begin with a lowercase letter. 变量名称应以lowercase字母开头。 Method names should also start with lowercase letters. 方法名称还应该以小写字母开头。 Class names and functions should begin with capital letters. 类名和功能应以大写字母开头。 It makes it difficult to read because I and many others have been trained to see capital letters and think CLASS NAME instead of POSSIBLE VARIABLE NAME. 由于我和许多其他人已经受过训练,可以看到大写字母并认为“类别名称”而不是“可能的变量名称”,因此很难阅读。 Just FYI 仅供参考

Finally, some of your methods take multiple parameters, like the one above. 最后,您的某些方法采用多个参数,例如上面的参数。 You really should add a prefix to each parameter so that it's easy to understand what the parameter is for. 您确实应该为每个参数添加一个前缀,以便于理解该参数的用途。 This: 这个:

[vdb SelectAsyncRequest: PARAMETER : PARAMETER];

would look much better if it was : 如果是,它将看起来更好:

[vdb selectAsyncRequestForParameter: PARAMETER withOtherParameter:OTHERPARAM];

EDIT: I also don't think you need so many autorelease pools. 编辑:我也不认为您需要那么多自动发布池。 The entire thing is wrapped in a big autorelease pool already. 整个内容已经包装在一个大型自动释放池中。

EDIT2: I also see a lot of release calls that aren't necessary. EDIT2:我还看到了很多不必要的release调用。 In your UploadChunkWise method you are calling release on *data and *returnedData which are both already implicitly autoreleased . 在您的UploadChunkWise方法中,您要对*data*returnedData调用release,它们已经隐式自动释放 Methods that return objects to you will already have ownership given up and "handed over" to you. 将对象返回给您的方法将已经拥有所有权并“移交给”您。 Essentially, those methods will do this: 本质上,这些方法可以做到这一点:

NSData *data = [[NSData alloc] init];
return [data autorelease];

When you get it, if you want to keep it you will have to retain it yourself, otherwise it will be destroyed at the return of your method. 当您获取它时,如果要保留它,则必须自己retain它,否则它将在方法返回时销毁。

However, it is correct for you to call release on the NSString *result instance you created with -init . 但是,对使用-init创建的NSString *result实例调用release是正确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM