Memory Management Policy
内存管理策略
The basic model used for memory management in a reference-counted environment is provided by a combination of methods defined in the NSObject protocol and a standard method naming convention. The NSObject class also defines a method, dealloc, that is invoked automatically when an object is deallocated. This article describes all the basic rules you need to know to manage memory correctly in a Cocoa program, and provides some examples of correct usage.
在引用计数环境下,内存管理使用的基本模型,是在NSObject协议中定义的方法和标准的方法命名规则的组合。NSObject类定义了一个方法,dealloc,它会在当一个对象被释放时自动调用。本文描述了您需要知道的所有基本规则,以便正确地管理Cocoa程序中的内存,并提供正确使用的一些示例。
#重点词汇 a combination of …的组合
Basic Memory Management Rules
基本内存管理法则
The memory management model is based on object ownership. Any object may have one or more owners. As long as an object has at least one owner, it continues to exist. If an object has no owners, the runtime system destroys it automatically. To make sure it is clear when you own an object and when you do not, Cocoa sets the following policy:
内存管理模型基于对象所有权。任何对象都可能有一个或多个所有者。只要一个对象有至少一个所有者,它就会一直存在。如果一个对象没有了所有者,那么运行时系统就会自动销毁这个对象。为了明确您什么时候拥有一个对象,什么时候销毁一个对象,Cocoa制定了以下规则:
- You own any object you create
- 你拥有任何你创建的对象
You create an object using a method whose name begins with "alloc", "new", "copy", or "mutableCopy" (for example, alloc, newObject, or mutableCopy).
你使用以alloc、new、copy或mutableCopy为开始的名字来创建一个对象。(例如:alloc,newObject,mutableCopy)
- You can take ownership of an object using retain
- 你可以使用retain来获得一个对象的所有权
A received object is normally guaranteed to remain valid within the method it was received in, and that method may also safely return the object to its invoker. You use retain
in two situations:
(1) In the implementation of an accessor method or an init
method, to take ownership of an object you want to store as a property value; and
(2) To prevent an object from being invalidated as a side-effect of some other
operation (as explained in Avoid Causing Deallocation of Objects You’re Using).
接收到的对象通常被保证在它被接受到的方法内持续有效,并且这个这个方法也可以安全地将对象返回给它的调用者。你在以下两种情况下会使用retain:
(1) 在一个存取方法或者初始化方法的实现中,获得一个你想存储为属性值的对象的所有权。
(2) 在执行某些其它操作时,防止对象被作废。(正如在Avoid Causing Deallocation of Objects You’re Using一问中所述)
- When you no longer need it, you must relinquish ownership of an object you own
- 当你不再需要它时,你必须放弃你所拥有对象的所有权
You relinquish ownership of an object by sending it a release message or an autorelease message. In Cocoa terminology, relinquishing ownership of an object is therefore typically referred to as “releasing” an object.
你通过发送释放消息或自动释放消息来放弃一个对象的所有权。在Cocoa的术语中,放弃一个对象的所有权通常被称为“释放”一个对象。
- You must not relinquish ownership of an object you do not own
- 你无法放弃一个你所不拥有的对象的所有权
This is just corollary of the previous policy rules, stated explicitly.
这只是明确陈述了以上政策规则的推论。
重点词汇
- relinquish 放弃; 让出; 放开,松手; 撤离
- terminology 专门名词; 术语,术语学; 用辞
- therefore 因此; 所以; 故; 乃
- referred to as 被称为…
- corollary 必然的结果,系,推论
A Simple Example
一个简单的例子
To illustrate the policy, consider the following code fragment:
为了阐述规则,请思考以下代码片段:
{ Person *aPerson = [[Person alloc] init]; // ... NSString *name = aPerson.fullName; // ... [aPerson release]; }
The Person object is created using the alloc method, so it is subsequently sent a release message when it is no longer needed. The person’s name is not retrieved using any of the owning methods, so it is not sent a release message. Notice, though, that the example uses release rather than autorelease.
Person对象是使用alloc方法创建的,所以随后当它不再被需要的时候会发送一个释放消息。Person对象的name没有用任何拥有的方法检索到,所以它不发送释放消息。注意,尽管如此,这个例子使用release而不是autorelease。
Use autorelease to Send a Deferred release
使用autorelease发送延迟释放
You use autorelease when you need to send a deferred release message—typically when returning an object from a method. For example, you could implement the fullName method like this:
当你需要发送一个延迟的释放消息时(通常当在一个方法中返回一个对象时),你会使用autorelease。例如,你可以像这样实现一个fullName方法:
- (NSString *)fullName { NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@", self.firstName, self.lastName] autorelease]; return string; }
You own the string returned by alloc. To abide by the memory management rules, you must relinquish ownership of the string before you lose the reference to it. If you use release, however, the string will be deallocated before it is returned (and the method would return an invalid object). Using autorelease, you signify that you want to relinquish ownership, but you allow the caller of the method to use the returned string before it is deallocated.
你拥有alloc方法返回的字符串的所有权。为了遵守内存管理法则,你必须在失去这个字符串的引用之前放弃它。如果你使用release,那么这个字符串将会在返回之前被释放掉。(并且这个方法将会返回一个无效对象)使用autorealease,意味着你想要放弃这个字符串的所有权,但是允许方法的调用者在返回的字符串被释放之前使用它。
You could also implement the fullName method like this:
你也可以像这样实现fullName方法:
- (NSString *)fullName { NSString *string = [NSString stringWithFormat:@"%@ %@",self.firstName, self.lastName]; return string; }
Following the basic rules, you don’t own the string returned by stringWithFormat:, so you can safely return the string from the method.
遵循基本规则,你不会拥有由stringWithFormat:方法返回的字符串,所以就可以安全地从方法返回字符串。
By way of contrast, the following implementation is wrong:
作为对比,以下的实现方式是错误的:
- (NSString *)fullName { NSString *string = [[NSString alloc] initWithFormat:@"%@ %@", self.firstName, self.lastName]; return string; }
According to the naming convention, there is nothing to denote that the caller of the fullName method owns the returned string. The caller therefore has no reason to release the returned string, and it will thus be leaked.
根据命名规则,并没有表明fullName方法的调用者拥有返回的字符串。因此调用者没有理由释放返回的字符串,并且字符串将会因此被泄漏。
重点词汇
- subsequently 其后,随后,接着; “subsequent”的派生; 嗣后; 尔后
- retrieved 恢复; 取回( retrieve的过去式和过去分词 ); 寻回; 检索
- deferred 延期的,缓召的; 拖延,延缓,推迟( defer的过去式和过去分
- abide by 遵守; 信守; 忠于; 接受
- relinquish 放弃; 让出; 放开,松手; 撤离
- signify 意味; 预示; 表示…的意思; 具有重要性,要紧; 辱骂
- By way of 路经; 途经; 作为; 意在
- contrast 对比,对照; 差异; 对照物,对立面; 反差; 对比; 形成对照;
- denote 代表; 指代; 预示; 意思是
You Don’t Own Objects Returned by Reference
你不会拥有引用返回的对象
Some methods in Cocoa specify that an object is returned by reference (that is, they take an argument of type ClassName **
or id *
). A common pattern is to use an NSError
object that contains information about an error if one occurs, as illustrated by initWithContentsOfURL:options:error: (NSData) and initWithContentsOfFile:encoding:error: (NSString).
Cocoa中的一些方法明确指出了对象是由引用返回的(那是因为他们携带了一个ClassName或者是id类型的参数)。常见的模式是如果发生错误使用包含错误信息的NSError对象,如NSData的initWithContentsOfURL:options:error:方法和NSString的initWithContentsOfFile:encoding:error:
方法所示。
In these cases, the same rules apply as have already been described. When you invoke any of these methods, you do not create the NSError object, so you do not own it. There is therefore no need to release it, as illustrated in this example:
在这些情况下,同样的规则应用已经被描述过了。当你调用这些方法时,你不创建NSError对象,所以你并不拥有它。因此无需释放它,如本例所示:
NSString *fileName = <#Get a file name#>; NSError *error; NSString *string = [[NSString alloc] initWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:&error]; if (string == nil) { // Deal with error... } // ... [string release];
Implement dealloc to Relinquish Ownership of Objects
实现dealloc来放弃对象的所有权
The NSObject
class defines a method, dealloc, that is invoked automatically when an object has no owners and its memory is reclaimed—in Cocoa terminology it is “freed” or “deallocated.”. The role of the dealloc
method is to free the object's own memory, and to dispose of any resources it holds, including ownership of any object instance variables.
NSObject类定义了一个方法,dealloc,当一个对象没有拥有者并且它的内存被回收(在Cocoa术语中叫“freed” 或者 “deallocated”),dealloc方法会被自动调用。dealloc方法的作用是释放对象拥有的内存,并且解决掉它拥有的任何资源,包括任何对象的实例变量。
The following example illustrates how you might implement a dealloc method for a Person class:
下面的例子解释了如何为一个Person类实现dealloc方法:
@interface Person : NSObject @property (retain) NSString *firstName; @property (retain) NSString *lastName; @property (assign, readonly) NSString *fullName; @end @implementation Person // ... - (void)dealloc [_firstName release]; [_lastName release]; [super dealloc]; } @end
Important: Never invoke another object’s dealloc
method directly.
不要直接调用另一个对象的dealloc方法。
You must invoke the superclass’s implementation at the end of your implementation.
你必须在你的实现的结尾调用父类的实现。
You should not tie management of system resources to object lifetimes; see Don’t Use dealloc to Manage Scarce Resources.
你不应该将系统资源的管理和对象的生命周期绑定在一起;参见Don’t Use dealloc to Manage Scarce Resources。
When an application terminates, objects may not be sent a dealloc
message. Because the process’s memory is automatically cleared on exit, it is more efficient simply to allow the operating system to clean up resources than to invoke all the memory management methods.
当一个应用程序终止时,对象可能不会发送dealloc消息。因为进程的内存在退出时会自动清除,允许操作系统清除资源比调用所有的内存管理方法更有效。
Core Foundation Uses Similar but Different Rules
Core Foundation 使用相似但不同的规则
There are similar memory management rules for Core Foundation objects (see Memory Management Programming Guide for Core Foundation). The naming conventions for Cocoa and Core Foundation, however, are different. In particular, Core Foundation’s Create Rule (see The Create Rule) does not apply to methods that return Objective-C objects. For example, in the following code fragment, you are not responsible for relinquishing ownership of myInstance
:
Core Foundation 对象有着相似的内存管理规则(参见Memory Management Programming Guide for Core Foundation)然而Cocoa和Core Foundation有着不同的命名规则。尤其是Core Foundation的创建规则(参见 The Create Rule)不适用于返回OC对象的方法。例如,在下面的代码块中,你不负责放弃myInstance对象的所有权:
MyClass *myInstance = [MyClass createInstance];
重点词汇
- invoke 乞灵,祈求; 提出或授引…以支持或证明; 召鬼; 借助
- reclaimed 再生的; 回收的; 翻造的; 收复的; 开拓( reclaim的过去式
- terminology 专门名词; 术语,术语学; 用辞
- dispose of 解决; 将处理掉; 驳倒; 将吃光喝完
- responsible for 为…负责,是造成…的原因