核心数据:NSObjectID和NSTemporaryObjectID泄漏 [英] Core Data: NSObjectID and NSTemporaryObjectID leaks
问题描述
在我将应用程序发送到App Store之前,我喜欢检查内存泄漏和其他鱼饵。有一个核心数据问题,我似乎无法解决,所以我决定创建一个小测试应用程序来说明这个问题。
当我将一个实体保存在一个(子)NSManagedObjectContext中时,它被传播到其父NSManagedObjectContext。在此过程中,Core Data创建 _NSObjectID
和 NSTemporaryObjectID
的内部实例。由于某些原因,这些实例被遗留下来,摆脱它们的唯一方法是重置父NSManagedObjectContext。
我的应用程序当然比这更复杂小测试应用和重置NSManagedObjectContext对我来说不是一个选项。
测试应用
$ b b
测试应用程序是一个基于单视图模板并选中CoreData选项的标准iOS应用程序。我使用objective-c保持它类似于我的生产应用程序。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//初始化核心数据栈
self.persistentStoreCoordinator = [self persistentStoreCoordinator];
//创建一个私有上下文
self.rootContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.rootContext.persistentStoreCoordinator = self.persistentStoreCoordinator;
//创建子上下文
self.childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.childContext.parentContext = self.rootContext;
//创建一个人
[self.childContext performBlockAndWait:^ {
Person * person = [NSEntityDescription insertNewObjectForEntityForName:@PersoninManagedObjectContext:self.childContext];
person.name = @John Smith;
person.age = 30;
//保存人
[self.childContext save:nil];
//保存根上下文
[self.rootContext performBlockAndWait:^ {
[self.rootContext save:nil];
}];
}];
return YES;
}
当您使用仪器和分配仪器运行上面的代码时,您可以看到
您可以在这里找到完整的项目:
我尝试的东西
我尝试过 :... mergeChanges:YES]
,添加 @autoreleasepool
和/或 [context processPendingChanges]
里面的块,这一切都没有帮助。清除它的唯一方法是执行 [上下文重置]
(大锤方法)。
找到其他人报告这个问题。
此博文似乎类似:
但是,我不知道我会关心,除非你看到很多这些,他们永远不会离开。我假定Core Data的内部(包括行缓存)有某种类型的对象缓存。
另一方面,我的Core Data使用已经改变了一点过去一两年。
除非是一个非常简单的应用程序,我几乎从不在子上下文中创建新对象。我将获取和修改它们,但如果我最终创建一个新的对象,我确保它是在兄弟的上下文中完成。
但是,如果你修改代码在初始保存之前,通过添加这一行(你有适当的错误处理 - 返回 BOOL
)
NSArray * inserted = self.childContext.insertedObjects.allObjects;
[self.childContext getsPermanentIDsForObjects:inserted error:& error];
你应该得到类似这样的仪器报告,它显示所有创建为瞬态的对象...
因此,我不一定认为是永久性泄漏,因为一旦我强制上下文转换为永久ID,对象就会消失。但是,谁知道它们保存这些对象ID对象的时间有多长。
一般来说,当我在包含层次结构的上下文中创建对象时,第一(出于很多原因)。但是,正如我之前所说,我通常在直接创建持久化存储的上下文中创建新对象(因为我不得不处理与层次结构临时对象ID相关的其他问题,特别是在使用多个非相关上下文时) / p>
Before I send my app to the App Store I like to check it for memory leaks and other fishy stuff with instruments. There is one Core Data issue that I can't seem to solve, so I've decided to create a small test app to illustrate the problem.
What's the problem?
When I save an entity in a (child) NSManagedObjectContext it is propagated to its parent NSManagedObjectContext. During this process Core Data creates internal instances of _NSObjectID
and NSTemporaryObjectID
. For some reason these instances are left behind and the only way to get rid of them is to reset the parent NSManagedObjectContext.
My app is of course a lot more complex than this little test app and resetting the NSManagedObjectContext isn't an option for me.
Test app
The test app is a standard iOS app based on the single view template with the CoreData option checked. I've used objective-c to keep it similar to my production app.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Initialize the Core Data stack
self.persistentStoreCoordinator = [self persistentStoreCoordinator];
// Create the a private context
self.rootContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.rootContext.persistentStoreCoordinator = self.persistentStoreCoordinator;
// Create a child context
self.childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.childContext.parentContext = self.rootContext;
// Create a person
[self.childContext performBlockAndWait:^{
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.childContext];
person.name = @"John Smith";
person.age = 30;
// Save the person
[self.childContext save:nil];
// Save the root context
[self.rootContext performBlockAndWait:^{
[self.rootContext save:nil];
}];
}];
return YES;
}
When you run the code above with instruments and the allocations instrument you can see that Core Data leaves some stuff behind.
You can find the full project here: https://github.com/Zyphrax/CoreDataLeak
Things I've tried
I've tried things like [context refreshObject:... mergeChanges:YES]
, adding @autoreleasepool
and/or [context processPendingChanges]
inside the blocks, it all doesn't help. The only way to get it clean is to do a [context reset]
(sledgehammer approach).
It's hard to find other people reporting this problem.
This blog post seems similar:
http://finalize.com/2013/01/04/core-data-issues-with-memory-allocation/
I hope you guys can help me with this.
Here is what I see, which is very similar to yours...
However, I don't know that I would be concerned, unless you see lots of these, and they never go away. I assume the internals of Core Data (including the row cache has) some sort of object caching going on.
On the other hand, my Core Data usage has changed a bit over the past year or two.
Unless it is a very simple app, I almost never create new objects in a child context. I will fetch and modify them, but if I end up creating a new object, I make sure that is done in a sibling context.
However, if you modify your code slightly, by adding this line (with your appropriate error handling - it returns BOOL
) before the initial save...
NSArray *inserted = self.childContext.insertedObjects.allObjects;
[self.childContext obtainPermanentIDsForObjects:inserted error:&error];
you should get something like this instruments report, which shows all objects created as being transient...
Thus, I don't necessarily think it is a permanent leak, because once I force the context to convert to a permanent ID, the objects go away. However, who knows how long they keep those object ID objects cached.
In general, when I create objects in a context that contains a hierarchy, I will always obtain permanent IDs first (for many reasons). However, as I said earlier, I usually create new objects in a context that is directly created to the persistent store (because I have had to deal with other issues related to hierarchies temporary object IDs, especially when using multiple non related contexts).
这篇关于核心数据:NSObjectID和NSTemporaryObjectID泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!