在我编写的过程中,我的应用程序在内存中上升,似乎没有释放它。
我想提到的第一件事是我所写的基本大纲是这样的:
- 请求一个 url(使用 NSData -initWithContentsOfURL 获取数据)
- 使用 NSJSONSerialization +JSONObjectWithStream 将 NSData 解析为 NSDictionarys 的 NSArray
- 循环解码NSArray 使用 FMDB 框架在 sqlite 数据库中插入/更新/删除记录并解码数据
应用程序执行上述操作,但是它在一个不确定的时间段内循环执行,其中应用程序显示“正在加载”HUD。我认为这可能值得一提,尽管我发现它执行此过程的次数无关紧要,因为如果它正确释放,这不应该影响内存使用。如果我在这里错了,请告诉我。
我的代码工作正常,嗯,它做了它打算做的事情。但是,当我分析应用程序代码时,内存似乎一直在增加。它确实在整个过程中有所下降,但总体而言它一直在上升(IE 没有完全释放它以前使用的内容)。
如前所述,我已经使用分配、泄漏、VM 跟踪器对应用程序进行了概要分析,并使用了跟踪亮点。
Trace Highlights:显示内存使用率逐渐上升,但减少了一些内存(不是全部),这意味着如果进程运行足够长的时间,内存将达到高使用率并终止。
分配:似乎还可以。分配有峰值,但总是回到它开始的地方。我拍了很多照片,它们总是下降,每段最多留下 500-700kb(留下大约 10 分钟)
VM Tracker:证明内存持续上升,并且没有释放全部内存(如跟踪亮点中所发现的)。居民似乎真的很高
泄漏:应用程序中未发现泄漏
这是 Allocations/VM Tracker 运行的一些屏幕截图:
值得注意的是,我实际上已经尝试过:
- 添加自动释放池
- 通过分配每个属性来“强制释放”;例如 NSURLs、NSRequests 等;为零
我的问题:
- 我应该做一些特别的事情来释放记忆吗?
- 我怎样才能进一步调试这个问题?
- 我怎样才能最好地从 Instruments 给我的数据中找出问题所在?
----编辑: ----
这是发送 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;
}
}
上面的方法是在应用程序委托中的 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;
}
以下是 -instantiateDatabaseQueue 方法:
-(FMDatabaseQueue *) instantiateDatabaseQueue {
@autoreleasepool {
return [FMDatabaseQueue databaseQueueWithPath: [self.getDocumentsDirectory stringByAppendingPathComponent:@"localdb.db"]];
}
}
autoreleasepools 可能会使它变得混乱,但代码最初没有这些。我在不同的地方实施了它们,看看是否有任何改进(没有)。
--- 编辑 3 ---
过去几天我一直在分析应用程序,但仍然没有找到答案。我已将有问题的应用程序部分分离到它自己的单独项目中,以确保它确实是导致内存使用的原因。事实证明这是正确的,因为该应用程序的行为仍然相同。
我已经拍摄了进一步的分析照片,但仍然很难确定到底是什么问题。看下面,分配看起来不错(VM 对我来说也不是太糟糕?),仍然没有泄漏(没有这个图片,因为没有!!)
但是,当我在 Trace Highlights 上进行分析时,内存使用量一直在上升,直到达到过多使用量(在 3GS 上约为 70+MB),然后由于使用太多内存而崩溃。
我通过使用 ASIHTTPRequest 来获取 NSData (改为存储到文件)来减少问题。请参阅上面的修改后的代码。但是,问题仍然存在,只是需要更长的时间才能发生!
按照最初的问题:
-此应用程序流程的第二部分有问题吗?