我目前正在努力应对我的应用程序的核心数据问题,这违反了我的逻辑。我确定我做错了但却看不清楚。
我正在我的核心数据实体上执行一个基本的executeFetchRequest,但是当我在iPhone上运行它时,似乎永远不会释放返回的托管对象数组,在模拟器下它完全按照预期工作。
尽管使用NSAutoreleasePool确保最小化内存占用。我还检查过Instruments并且没有泄漏,只是增加了内存分配(通过'[NSManagedObject(_PFDynamicAccessorsAndPropertySupport)allocWithEntity:]')。在我的实际应用中,这最终会导致didReceiveMemoryWarning调用。
我制作了一个最小程序,可以重现下面的问题。我已经尝试了各种各样的事情,例如在排空游泳池之前将所有物体发生故障,但没有任何乐趣。如果我提供一个指向fetch的NSError指针,则不会返回错误。没有后台线程在运行。
#import <mach/mach.h>
#import <mach/mach_host.h>
+(natural_t) get_free_memory {
mach_port_t host_port;
mach_msg_type_number_t host_size;
vm_size_t pagesize;
host_port = mach_host_self();
host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
host_page_size(host_port, &pagesize);
vm_statistics_data_t vm_stat;
if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS) {
NSLog(@"Failed to fetch vm statistics");
return 0;
}
/* Stats in bytes */
natural_t mem_free = vm_stat.free_count * pagesize;
return mem_free;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Set up the edit and add buttons.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject)];
self.navigationItem.rightBarButtonItem = addButton;
[addButton release];
// Obtain the Managed Object Context
NSManagedObjectContext *context = [(id)[[UIApplication sharedApplication] delegate] managedObjectContext];
// Check the free memory before we start
NSLog(@"INITIAL FREEMEM: %d", [RootViewController get_free_memory]);
// Loop around a few times
for(int i=0; i<20; i++) {
// Create an autorelease pool just for this loop
NSAutoreleasePool *looppool = [[NSAutoreleasePool alloc] init];
// Check the free memory each time around the loop
NSLog(@"FREEMEM: %d", [RootViewController get_free_memory]);
// Create a minimal request
NSEntityDescription *entityDescription = [NSEntityDescription
entityForName:@"TestEntity" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
// Perform the fetch
NSArray *array = [context executeFetchRequest:request error:nil];
[request release];
// Drain the pool - should release the fetched managed objects?
[looppool drain];
}
// Check the free menory at the end
NSLog(@"FINAL FREEMEM: %d", [RootViewController get_free_memory]);
}
当我在模拟器上运行上面的内容时,我得到以下输出(这看起来对我来说合理):
2011-06-06 09:50:28.123 renniksoft[937:207] INITIAL FREEMEM: 14782464
2011-06-06 09:50:28.128 renniksoft[937:207] FREEMEM: 14807040
2011-06-06 09:50:28.135 renniksoft[937:207] FREEMEM: 14831616
2011-06-06 09:50:28.139 renniksoft[937:207] FREEMEM: 14852096
2011-06-06 09:50:28.142 renniksoft[937:207] FREEMEM: 14872576
2011-06-06 09:50:28.146 renniksoft[937:207] FREEMEM: 14897152
2011-06-06 09:50:28.149 renniksoft[937:207] FREEMEM: 14917632
2011-06-06 09:50:28.153 renniksoft[937:207] FREEMEM: 14938112
2011-06-06 09:50:28.158 renniksoft[937:207] FREEMEM: 14962688
2011-06-06 09:50:28.161 renniksoft[937:207] FREEMEM: 14983168
2011-06-06 09:50:28.165 renniksoft[937:207] FREEMEM: 14741504
2011-06-06 09:50:28.168 renniksoft[937:207] FREEMEM: 14770176
2011-06-06 09:50:28.174 renniksoft[937:207] FREEMEM: 14790656
2011-06-06 09:50:28.177 renniksoft[937:207] FREEMEM: 14811136
2011-06-06 09:50:28.182 renniksoft[937:207] FREEMEM: 14831616
2011-06-06 09:50:28.186 renniksoft[937:207] FREEMEM: 14589952
2011-06-06 09:50:28.189 renniksoft[937:207] FREEMEM: 14610432
2011-06-06 09:50:28.192 renniksoft[937:207] FREEMEM: 14630912
2011-06-06 09:50:28.194 renniksoft[937:207] FREEMEM: 14651392
2011-06-06 09:50:28.197 renniksoft[937:207] FREEMEM: 14671872
2011-06-06 09:50:28.200 renniksoft[937:207] FREEMEM: 14692352
2011-06-06 09:50:28.203 renniksoft[937:207] FINAL FREEMEM: 14716928
但是,当我在实际的iPhone 4(4.3.3)上运行时,我得到以下结果:
2011-06-06 09:55:54.341 renniksoft[4727:707] INITIAL FREEMEM: 267927552
2011-06-06 09:55:54.348 renniksoft[4727:707] FREEMEM: 267952128
2011-06-06 09:55:54.702 renniksoft[4727:707] FREEMEM: 265818112
2011-06-06 09:55:55.214 renniksoft[4727:707] FREEMEM: 265355264
2011-06-06 09:55:55.714 renniksoft[4727:707] FREEMEM: 264892416
2011-06-06 09:55:56.215 renniksoft[4727:707] FREEMEM: 264441856
2011-06-06 09:55:56.713 renniksoft[4727:707] FREEMEM: 263979008
2011-06-06 09:55:57.226 renniksoft[4727:707] FREEMEM: 264089600
2011-06-06 09:55:57.721 renniksoft[4727:707] FREEMEM: 263630848
2011-06-06 09:55:58.226 renniksoft[4727:707] FREEMEM: 263168000
2011-06-06 09:55:58.726 renniksoft[4727:707] FREEMEM: 262705152
2011-06-06 09:55:59.242 renniksoft[4727:707] FREEMEM: 262852608
2011-06-06 09:55:59.737 renniksoft[4727:707] FREEMEM: 262389760
2011-06-06 09:56:00.243 renniksoft[4727:707] FREEMEM: 261931008
2011-06-06 09:56:00.751 renniksoft[4727:707] FREEMEM: 261992448
2011-06-06 09:56:01.280 renniksoft[4727:707] FREEMEM: 261574656
2011-06-06 09:56:01.774 renniksoft[4727:707] FREEMEM: 261148672
2011-06-06 09:56:02.290 renniksoft[4727:707] FREEMEM: 260755456
2011-06-06 09:56:02.820 renniksoft[4727:707] FREEMEM: 260837376
2011-06-06 09:56:03.334 renniksoft[4727:707] FREEMEM: 260395008
2011-06-06 09:56:03.825 renniksoft[4727:707] FREEMEM: 259932160
2011-06-06 09:56:04.346 renniksoft[4727:707] FINAL FREEMEM: 259555328
每次循环循环时,可用内存量与我获取的托管对象成比例减少。如果我获取两倍的对象,则可用内存减少两倍 - 所以我非常有信心它是未被释放的托管对象。
请注意,正在获取的实体非常基本,只有两个属性,一个字符串和一个16位整数。在上面的例子中有1000个被提取。我用来生成它们的代码如下:
// Create test entities
for(int i=0; i<1000; i++) {
id entity = [NSEntityDescription insertNewObjectForEntityForName:@"TestEntity" inManagedObjectContext:context];
[entity setValue:[NSString stringWithFormat:@"%d",i] forKey:@"name"];
[entity setValue:[NSNumber numberWithInt:i] forKey:@"value"];
}
if (![context save:nil]) {
NSLog(@"Couldn't save");
}
如果有人能向我解释发生了什么,我将非常感激!此问题是唯一一个阻止我的应用发布的问题。它在模拟器上运行得很漂亮!!
如果我能提供更多信息,请告诉我。
答案 0 :(得分:1)
卫生署!这就是我看起来愚蠢的地方!
我将'NSZombieEnabled'设置为YES,这意味着获取的数据未被释放!没有这个,一切正常: - )
答案 1 :(得分:0)
我没有MacOs设备,我现在可以测试了。但我发现你没有注册NSFetchRequest进行自动释放。
我会尝试这种方法:
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];