我的应用程序,在我编写的过程中,在内存中上升,似乎没有释放它。
我首先要提到的是,我所写的基本概要是这样的:
- 请求URL(使用NSData -initWithContentsOfURL获取数据)
- 使用NSJSONSerialization + JSONObjectWithStream将NSData解析为NSDictionarys的NSArray
- 使用已解码数据的FMDB框架在sqlite数据库中循环解码NSArray插入/更新/删除记录
应用程序执行上述操作,但它会在一个循环中执行一段不确定的时间,其中应用程序显示“正在加载”HUD。我认为值得一提的是,虽然我发现这个过程有多少次无关紧要,因为如果它正确释放,它不应该影响内存使用量。如果我在这里错了,请告诉我。
我的代码工作正常,嗯,它完成了它的目的。但是,当我分析应用程序代码时,内存似乎只是不断上升。它确实在各个部分都有所下降,但总体而言它不断上升(IE不会完全释放它之前使用的内容)。
如前所述,我已使用Allocations,Leaks,VM Tracker和使用的Trace Highlights对应用程序进行了分析。
跟踪突出显示:显示内存使用量逐渐增加,但丢失了一些内存(并非全部),这意味着如果进程运行的时间足够长,内存将达到高使用率并终止。< / p>
分配:似乎没问题。分配有峰值,但总是回到它开始的地方。我拍了快照,他们总是下降,每段最多留下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;
}
}
从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;
}
以下是-instantiateDatabaseQueue方法:
-(FMDatabaseQueue *) instantiateDatabaseQueue {
@autoreleasepool {
return [FMDatabaseQueue databaseQueueWithPath: [self.getDocumentsDirectory stringByAppendingPathComponent:@"localdb.db"]];
}
}
自动释放池可能会使它变得混乱,但代码最初没有这些。我在不同的地方实施了它们,看看是否有任何改进(没有)。
---编辑3 ---
过去几天我一直在分析应用程序,但仍然没有找到答案。我已将相关应用程序的部分分离到它自己的单独项目中,以确保它确实会导致内存使用。事实证明这是正确的,因为应用程序的行为仍然相同。
我已经对图片进行了进一步的分析,我仍然很难确定究竟是什么问题。看下面的分配看起来还不错(VM对我来说也不是太糟糕了?),而且还没有泄漏(没有这个图片,因为没有!)
然而,当我在Trace Highlights上进行分析时,内存使用率一直在上升,直到达到过多的使用率(3GS上大约70 + MB),然后由于使用了这么多内存而崩溃。
我通过使用ASIHTTPRequest来获取NSData(而不是存储到文件)来减少了问题。请参阅上面的修订代码。然而,问题仍然存在,只需要更长的时间!
原来,问题:
- 此应用程序流程的第二部分是否有问题?
答案 0 :(得分:1)
在iOS中使用带有ARC的try / catch可能会导致内存泄漏,最好避免使用。
另一种方法是使用异步NSURLConnection,或使用同步NSURLConnection的NSOperation。