我的应用程序在我写的过程中会出现内存上升并似乎没有释放的情况。
首先要提及的是,我所编写的基本概述如下:
- 请求URL(使用NSData-initWithContentsOfURL获取数据)
- 使用NSJSONSerialization +JSONObjectWithStream将NSData解析为NSDictionary的NSArray
- 通过FMDB框架循环插入/更新/删除记录到sqlite数据库中,使用解码的数据
应用程序执行以上操作,但它会在一个未确定的时间段内循环执行这些操作并显示“加载”HUD。虽然我认为它执行此过程的次数并不重要,但如果它能正确释放内存,那么这不会影响内存使用情况。如果我在这里错了,请告诉我。
我的代码运行得很好,它做到了它的预期目标。然而,当我分析应用程序代码时,内存似乎一直在上升。虽然它在某些地方会降低,但总体上它仍在上升(即先前使用的内存没有完全释放)。
正如先前提到的,我使用了Allocations、Leaks、VM Tracker和Trace Highlights等工具对应用程序进行了分析。
- Trace Highlights:显示内存使用量逐渐增加,但会释放一些内存(但不是全部),这意味着如果进程运行足够长时间,内存将达到高使用率并终止。 - Allocations:看起来还好。分配有所波动,但总是回到起点。我拍了heapshots,它们总是下降到留下每个段的最大500-700kb(保持10分钟左右)。 - VM Tracker:证明内存一直在不断上升,而且没有完全释放内存(如在Trace Highlights中发现的)。Resident似乎非常高。 - Leaks:应用程序中未发现泄漏。
以下是运行Allocations/VM Tracker的一些屏幕截图:
值得注意的是,我确实尝试过:
- 添加autorelease池
- 通过将每个属性(例如NSURL、NSRequest等)指定为nil来“强制释放”。
我的问题:
- 我是否需要做一些特殊的事情来释放内存?
- 如何进一步调试此问题?
- 最好如何从Instruments给出的数据中找出问题?
----编辑:----
以下是发送URL请求以获取数据的代码:
以下是 -instantiateDatabaseQueue 方法的内容:
实例化数据库队列方法:
自动释放池可能会使代码变得混乱,但是原始代码并没有这些。我在各个位置实现了它们,以查看是否有任何改进(但实际上没有)。
---编辑3---
过去几天里,我一直在对应用程序进行分析,但仍然没有找到答案。我将问题部分分离到了一个单独的项目中,以确保它确实导致了内存使用情况。这被证明是正确的,因为该应用程序仍然表现出相同的问题。
我已经进一步进行了分析,并且仍然很难确定实际上出了什么问题。如下所示,分配看起来还不错(虚拟内存对我来说也不太糟糕?),而且没有泄漏(没有图片,因为没有!)
然而,在Trace Highlights 上进行分析时,内存使用量不断增加,直到达到太多使用量(在 3GS 上大约为 70MB),然后因使用太多内存而崩溃。
我通过使用 ASIHTTPRequest 来获取 NSData(存储到文件中)来缓解问题。请参见上面的修订代码。但是,问题仍然存在,只是需要更长时间才能发生!
与最初的问题相同: - 这个应用程序进程的第二部分有什么问题吗?
首先要提及的是,我所编写的基本概述如下:
- 请求URL(使用NSData-initWithContentsOfURL获取数据)
- 使用NSJSONSerialization +JSONObjectWithStream将NSData解析为NSDictionary的NSArray
- 通过FMDB框架循环插入/更新/删除记录到sqlite数据库中,使用解码的数据
应用程序执行以上操作,但它会在一个未确定的时间段内循环执行这些操作并显示“加载”HUD。虽然我认为它执行此过程的次数并不重要,但如果它能正确释放内存,那么这不会影响内存使用情况。如果我在这里错了,请告诉我。
我的代码运行得很好,它做到了它的预期目标。然而,当我分析应用程序代码时,内存似乎一直在上升。虽然它在某些地方会降低,但总体上它仍在上升(即先前使用的内存没有完全释放)。
正如先前提到的,我使用了Allocations、Leaks、VM Tracker和Trace Highlights等工具对应用程序进行了分析。
- Trace Highlights:显示内存使用量逐渐增加,但会释放一些内存(但不是全部),这意味着如果进程运行足够长时间,内存将达到高使用率并终止。 - Allocations:看起来还好。分配有所波动,但总是回到起点。我拍了heapshots,它们总是下降到留下每个段的最大500-700kb(保持10分钟左右)。 - VM Tracker:证明内存一直在不断上升,而且没有完全释放内存(如在Trace Highlights中发现的)。Resident似乎非常高。 - Leaks:应用程序中未发现泄漏。
以下是运行Allocations/VM Tracker的一些屏幕截图:
![enter image description here](https://istack.dev59.com/YBOam.webp)
![enter image description here](https://istack.dev59.com/Ap3LS.webp)
- 添加autorelease池
- 通过将每个属性(例如NSURL、NSRequest等)指定为nil来“强制释放”。
我的问题:
- 我是否需要做一些特殊的事情来释放内存?
- 如何进一步调试此问题?
- 最好如何从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"]];
}
}
自动释放池可能会使代码变得混乱,但是原始代码并没有这些。我在各个位置实现了它们,以查看是否有任何改进(但实际上没有)。
---编辑3---
过去几天里,我一直在对应用程序进行分析,但仍然没有找到答案。我将问题部分分离到了一个单独的项目中,以确保它确实导致了内存使用情况。这被证明是正确的,因为该应用程序仍然表现出相同的问题。
我已经进一步进行了分析,并且仍然很难确定实际上出了什么问题。如下所示,分配看起来还不错(虚拟内存对我来说也不太糟糕?),而且没有泄漏(没有图片,因为没有!)
然而,在Trace Highlights 上进行分析时,内存使用量不断增加,直到达到太多使用量(在 3GS 上大约为 70MB),然后因使用太多内存而崩溃。
我通过使用 ASIHTTPRequest 来获取 NSData(存储到文件中)来缓解问题。请参见上面的修订代码。但是,问题仍然存在,只是需要更长时间才能发生!
与最初的问题相同: - 这个应用程序进程的第二部分有什么问题吗?