iOS [ARC]应用程序不释放内存

Jos*_*hua 10 memory cocoa-touch ios

在我编写的一个过程中,我的应用程序在内存中上升,似乎没有释放它.

我要提到的第一件事是我写的基本概要是:
- 请求一个url(使用NSData -initWithContentsOfURL获取数据)
- 使用NSJSONSerialization + JSONObjectWithStream 将NSData 解析为NSDictionarys的NSArray
- 循环解码NSArray使用FMDB框架在sqlite数据库中插入/更新/删除记录,并对数据进行解码

应用程序执行上述操作,但是它会在一个循环中执行一段不确定的时间,其中应用程序显示"正在加载"HUD.我认为值得一提的是,虽然我发现这个过程有多少次无关紧要,因为如果它正确释放,它不应该影响内存使用量.如果我在这里错了,请告诉我.

我的代码运行良好,嗯,它完成了它的目的.但是,当我分析应用程序代码时,内存似乎只是不断上升.它确实在各个部分都有所下降,但总体而言它不断上升(IE不会完全释放它之前使用的内容).

如前所述,我已使用Allocations,Leaks,VM Tracker和使用的Trace Highlights对应用程序进行了分析.

跟踪要点:显示内存使用量逐渐增加,但丢失了一些内存(并非全部),这意味着如果进程运行的时间足够长,内存将达到高使用率并终止.

分配:似乎没问题.分配有峰值,但总是回到它开始的地方.我拍了快照,他们总是下降,每段最多留下500-700kb(左边大约10分钟)

VM Tracker:证明显示内存持续增加,并且没有释放完整内存(在跟踪突出显示中发现).居民似乎变得非常高

泄漏:应用中未发现泄漏

以下是Allocations/VM Tracker运行的一些截图:
在此输入图像描述 在此输入图像描述

值得注意的是,我实际上尝试过:
- 添加autoreleasepools
- 通过分配每个属性来"强制释放"; 例如NSURL,NSRequests等; 没有

我的问题:
- 我应该做一些特别的事情来释放记忆吗?
- 我怎么能进一步调试这个问题?
- 如何才能最好地找出仪器给我的数据有什么问题?

---- 编辑: ----
这是发送url请求获取数据的代码:

- (void) requestAndParse : (NSString *)url 
{
    NSURL *theURL;
    ASIHTTPRequest *request;
    NSData *collectedData;
    NSError *error;
    @try {
                    // File cache the NSData
                    theURL = [[NSURL alloc] initWithString: url];
                    request = [ASIHTTPRequest requestWithURL: theURL];
                    [request setDownloadDestinationPath: [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingString:@"/cachefile.txt"]];
                    [request startSynchronous];
                    [request waitUntilFinished];

                    collectedData = [[NSData alloc] initWithContentsOfFile:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingString:@"/cachefile.txt"]];


                    if ([collectedData length] > 0) {
                        records = [NSJSONSerialization JSONObjectWithData:collectedData options:NSJSONReadingMutableContainers error:&error];
                    }

    }
    @catch (NSException *exception) {

                    // Failed
                    NSLog(@"Parse error: %@", error);

    }
    @finally {

                    // DB updates with the records here
                    ...

                    // remove file
                    [[NSFileManager defaultManager] removeItemAtPath:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingString:@"/cachefile.txt"] error:nil];
                    // release properties used
                    collectedData = nil;
                    request = nil;
                    theURL = nil;
    }

}
Run Code Online (Sandbox Code Playgroud)

上面的方法是从Application Delegate中的while循环中调用的.如前所述,while循环是未确定的长度.

---编辑2:---

以下是@finally语句(使用FMDB更新SQLite数据库)中发生的情况.我的课程中有很多这样的方法,每个表一个.它们都遵循相同的模式,因为它们都是从第一个复制的:

-(BOOL) insertBatchOfRecords:(NSArray *)records {

__block BOOL queueReturned = YES;

@autoreleasepool {

    FMDatabaseQueue *dbQueue = [self instantiateDatabaseQueue];
    [dbQueue inTransaction:^(FMDatabase *tdb, BOOL *rollback) {
        if (![tdb open]) {
            NSLog(@"Couldn't open DB inside Transaction");
            queueReturned = NO;
            *rollback = YES;
            return;
        }

        for (NSDictionary *record in records) {
            [tdb executeUpdate:@"INSERT OR REPLACE INTO table (attr1, attr2) VALUES (?,?)", [record valueForKey:@"attr1"], [record valueForKey:@"attr2"]];

            if ([tdb hadError]) {
                queueReturned = NO;
                *rollback = YES;
                NSLog(@"Failed to insert records because %@", [tdb lastErrorMessage]);
                return;
            }
        }
    }];

    [dbQueue close];
    dbQueue = nil;

}

return queueReturned;
}
Run Code Online (Sandbox Code Playgroud)

以下是-instantiateDatabaseQueue方法:

-(FMDatabaseQueue *) instantiateDatabaseQueue {
@autoreleasepool {
    return [FMDatabaseQueue databaseQueueWithPath: [self.getDocumentsDirectory stringByAppendingPathComponent:@"localdb.db"]];
}
}
Run Code Online (Sandbox Code Playgroud)

自动释放池可能会使它变得混乱,但代码最初没有这些.我在不同的地方实施了它们,看看是否有任何改进(没有).

---编辑3 ---

我过去几天一直在分析应用程序,但仍然没有找到答案的运气.我已将相关应用程序的部分分离到它自己的单独项目中,以确保它确实会导致内存使用.事实证明这是正确的,因为应用程序的行为仍然相同.

我已经进一步分析了图片,我仍然很难确定究竟是什么问题.看下面的分配看起来还不错(VM对我来说也不是太糟糕了?),而且仍然没有泄漏(没有这个的图片,因为没有!)

然而,当我在Trace Highlights上进行分析时,内存使用率一直在上升,直到达到过多的使用率(3GS上大约70 + MB),然后由于使用了这么多内存而崩溃.

在此输入图像描述

在此输入图像描述

在此输入图像描述

在此输入图像描述

在此输入图像描述

我通过使用ASIHTTPRequest来获取NSData(存储到文件)来减少了问题.请参阅上面的修订代码.然而,问题仍然存在,只需要更长的时间!

按照原来的问题:
- 此应用程序流程的第二部分是否有问题?

小智 1

在 iOS 中使用 try / catch 和 ARC 可能会导致内存泄漏,最好避免。

另一种方法是使用异步 NSURLConnection 或带有同步 NSURLConnection 的 NSOperation。