简体   繁体   English

Objective-C记忆模型

[英]Objective-C memory model

I am attempting to wrap my head around one part of the Objective-C memory model (specifically on the iPhone, so no GC). 我试图将我的头缠在Objective-C内存模型的一部分上(特别是在iPhone上,因此没有GC)。 My background is C/C++/Java, and I am having an issue with the following bit of code (also wondering if I am doing this in an "Objective-C way" or not): 我的背景是C / C ++ / Java,下面的代码存在问题(也想知道我是否以“ Objective-C方式”执行此操作):

- (NSSet *) retrieve
{
    NSMutableSet *set;

    set = [NSMutableSet new];
    // would normally fill the set in here with some data

    return ([set autorelease]);
}

- (void) test
{
    NSSet *setA;
    NSSet *setB;

    setA = [self retrieve];
    setB = [[self retrieve] retain];

    [setA release];
    [setB release];
}

start EDIT 开始编辑

Based on comments below, the updated retrieve method: 根据以下注释,更新了检索方法:

- (NSSet *) retrieve
{
    NSMutableSet *set;

    set = [[[NSMutableSet alloc] initWithCapacity:100] autorelease];
    // would normally fill the set in here with some data

    return (set);
}

end EDIT 结束编辑

The above code gives a warning for [setA release] "Incorrect decrement of the reference count of an object is not owned at this point by the caller". 上面的代码为[setA release]提供了警告“调用者此时不拥有对象引用计数的不正确减少”。

I though that the "new" set the reference count to 1. Then the "retain" call would add 1, and the "release" call would drop it by 1. Given that wouldn't setA have a reference count of 0 at the end and setB have a reference count of 1 at the end? 我虽然说“ new”将引用计数设置为1,但是“ retain”调用将添加1,而“ release”调用会将其删除1。给定的情况是setA的引用计数不会为0。 end和setB的引用计数最终是否为1?

From what I have figured out by trial and error, setB is correct, and there is no memory leak, but I'd like to understand why that is the case (what is wrong with my understanding of "new", "autorelease", "retain", and "release"). 根据我的尝试和发现,setB是正确的,并且没有内存泄漏,但是我想了解为什么会这样(我对“ new”,“ autorelease”的理解有什么问题, “保留”和“释放”)。

I though that the "new" set the reference count to 1. Then the "retain" call would add 1, and the "release" call would drop it by 1. Given that wouldn't setA have a reference count of 0 at the end and setB have a reference count of 1 at the end? 我虽然说“ new”将引用计数设置为1,但是“ retain”调用将添加1,而“ release”调用会将其删除1。给定的情况是setA的引用计数不会为0。 end和setB的引用计数最终是否为1?

You're leaving out the autorelease . 您将autorelease When -(void)test gets a set, its retain count is 0. You don't retain setA , so it already has a retain count of 0 when you try to release it, hence the error message. -(void)test得到一个集合时,它的保留计数为0。您没有保留setA ,因此当您尝试释放它时,它的保留计数已经为0,因此会出现错误消息。

The fundamental rule for memory management is quite simple: calls to alloc , new and copy* must be balanced by calls to release / autorelease . 内存管理基本规则非常简单:对allocnewcopy*的调用必须通过对release / autorelease调用来平衡。 The former take ownership, the latter relinquish ownership. 前者取得所有权,后者放弃所有权。

The only tricky part is when dealing with shared objects , where you don't take ownership of an object, so it might be discarded in between the time you get a reference to it and when you use it. 唯一棘手的部分是在处理共享库时 ,您不拥有对象的所有权,因此在您获得对它的引用与使用之间,它可能会被丢弃。 This has a simple solution: if in doubt, retain it. 这有一个简单的解决方案:如有疑问,请保留它。

You can make things even simpler by using properties in many situations. 通过在许多情况下使用属性 ,可以使事情变得更加简单。

Don't think in terms of absolute numbers. 不要以绝对数字来思考。 That can be very deceptive. 那可能是非常具有欺骗性的。 Think of retains and releases as deltas if you must have a number — in this case, the autorelease has already balanced the new (a +1 delta and a -1 delta), so that method manages its memory correctly and the receiver doesn't need to do anything unless it wants to keep the object around longer. 如果您必须有一个数字,则将保留和释放视为增量-在这种情况下, autorelease已使new平衡(+1增量和-1增量),因此该方法可以正确地管理其内存,而接收方则不会需要做任何事情,除非它想让对象保持更长的时间。

Definitely read the memory management docs . 一定要阅读内存管理文档 It really is as simple as following the rules described there. 确实很简单,只需遵循此处描述的规则。 It's a very simple contract of ownership where you claim ownership when you want an object to stick around and relinquish ownership when you don't care anymore. 这是一个非常简单的所有权合同,当您希望对象随处可见时,您可以主张所有权;而当您不再关心对象时,则放弃所有权。 In the case above, you relinquish ownership in the retrieve method, so trying to relinquish ownership when you don't have it is obviously a bug. 在上述情况下,您在retrieve方法中放弃了所有权,因此,在没有所有权时尝试放弃所有权显然是一个错误。

As the profiler message hints, you should be thinking in terms of ownership. 正如探查器消息提示的那样,您应该考虑所有权。 As noted in the memory management rules , whenever you have an object that you have created with +alloc , +new , -copy , or -mutableCopy , you own it and are responsible for releasing it eventually. 内存管理规则中所述 ,每当您拥有使用+alloc+new-copy-mutableCopy创建的对象时,便拥有该对象并最终负责释放它。 (In fact, +new is just shorthand for [[MyClass alloc] init] .) (实际上, +new只是[[MyClass alloc] init]简写。)

-retain takes an object that you didn't initially own and makes you own it. -retain接受一个您最初不拥有的对象,并使您拥有它。

-release takes an object that you own and releases ownership of it. -release获取您拥有的对象并释放其所有权。

-autorelease takes an object that you own and releases ownership of it, but also guarantees that the object will exist for at least a little bit longer . -autorelease获取您拥有的对象并释放其所有权, 但也保证该对象至少存在一点时间

Your -retrieve method does not transfer ownership of the object it returns. 您的-retrieve方法不会转移它返回的对象的所有权。 This is good—it follows the memory management rules (the method isn't +alloc , +new , -copy , or -mutableCopy ). 很好-它遵循内存管理规则(该方法不是+alloc+new-copy-mutableCopy )。 Therefore, using -release on it without using -retain is an error. 因此,在不使用-retain情况下使用-release是错误的。 It would be equally valid to not retain or release the result from -retrieve , as long as the object will have a temporary lifetime—your -autorelease guarantees temporary existence of the object. 只要对象具有临时生存期,不保留或释放-retrieve的结果同样有效—您的-autorelease保证对象的临时存在。

http://www.macresearch.org/difference-between-alloc-init-and-new http://www.macresearch.org/difference-between-alloc-init-and-new

You probably want 你可能想要

NSMutableSet *set = [[NSMutableSet alloc] initWithCapacity: someNumber];

or 要么

NSMutableSet *set = [NSMutableSet setWithCapacity: someNumber];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM