天天看点

实际内存管理(Practical Memory Management)

实际内存管理(Practical Memory Management)

原文:PracticalMemory Management

使用访问器(get/set)方法来使得内存管理更加容易

 在init 和dealloc 方法中,不能使用get/set方法

使用弱引用,以避免循环保留(Use Weak References to Avoid Retain Cycles)

Retaining anobject creates a strong reference to that object. An object cannot bedeallocated until all of its strong references are released. A problem, knownas a retain cycle, can therefore arise if two objects may have cyclicalreferences—that is, they have a strong reference to each other (eitherdirectly, or through a chain of other objects each with a strong reference tothe next leading back to the first).

为一个需要保留的对象创建一个强引用。一个对象不能被收回,直到所有的强引用被释放。一个问题,即一个循环保留,因此如果两个物体可能会出现循环的引用是,他们有一个强引用彼此(直接或通过一连串的其他对象,每个对象都与一个强引用到下一个领先的回第一)。

The objectrelationships shown in Figure 1 illustrate a potential retain cycle. TheDocument object has a Page object for each page in the document. Each Pageobject has a property that keeps track of which document it is in. If theDocument object has a strong reference to the Page object and the Page objecthas a strong reference to the Document object, neither object can ever bedeallocated. The Document’s reference count cannot become zero until the Pageobject is released, and the Page object won’t be released until the Documentobject is deallocated.

对象关系如图1说明了一个潜在的循环保留。Document对象有一个Page对象中每一页面文档。每个页面对象有一个属性,跟踪哪个文档在。如果文档对象有一个强引用页面对象和页面对象有一个强引用文档对象,无论是对象会被收回。文档的引用计数不能成为零直到页面对象被释放,并且页面对象之后才会公布文档对象是重新分配的。

相互引用,导致死锁。

The solution tothe problem of retain cycles is to use weak references. A weak reference is anon-owning relationship where the source object does not retain the object towhich it has a reference.

解决问题的循环引用是使用弱引用。弱引用是一个非拥有关系,其中源对象不会保留对象,它有一个参考。

To keep the objectgraph intact, however, there must be strong references somewhere (if there wereonly weak references, then the pages and paragraphs might not have any ownersand so would be deallocated). Cocoa establishes a convention, therefore, that a“parent” object should maintain strong references to its “children,” and thatthe children should have weak references to their parents.

保持对象图的完整,但是,必须有强引用某个地方(如果只有弱引用,那么这个页面和段落可能没有任何所有者,所以会被收回)。cocoa建立一个约定,因此,一个“父”对象应该保持强引用它的“孩子”,孩子们应该有弱引用他们的父母。

So, in Figure 1the document object has a strong reference to (retains) its page objects, butthe page object has a weak reference to (does not retain) the document object.

因此,在图1文档对象有一个强引用(保留)其页面对象,但页面对象有一个弱引用(不保留)文档对象。

Examplesof weak references in Cocoa include, but are not restricted to, table datasources, outline view items, notification observers,and miscellaneous targets anddelegates.

You need to becareful about sending messages to objects for which you hold only a weakreference. If you send a message to an object after it has been deallocated,your application will crash. You must have well-defined conditions for when theobject is valid. In most cases, the weak-referenced object is aware of theother object’s weak reference to it, as is the case for circular references,and is responsible for notifying the other object when it deallocates.

你必须仔细了解向对象发送消息,你持有只有弱引用。如果你发送消息到一个对象分配后,您的应用程序将会崩溃。你必须有一个明确的条件,当对象是有效的。在大多数情况下,弱引用的对象是意识到其他对象的弱引用,类似于循环引用,并负责通知其他对象当它重新分配。

For example, whenyou register an object with a notification center, the notification centerstores a weak reference to the object and sends messages to it when theappropriate notifications are posted. When the object is deallocated, you needto unregister it with the notification center to prevent the notificationcenter from sending any further messages to the object, which no longer exists.Likewise, when a delegate object is deallocated, you need to remove thedelegate link by sending a setDelegate: message with a nil argument to theother object. These messages are normally sent from the object’s deallocmethod.

例如,当你注册一个对象与一个通知中心,通知中心存储对象的弱引用和在适当的通知时,发生消息。当对象被收回,您需要注销它与通知预防中心关系。通知中心发送任何进一步的消息发送到该对象,该对象都不存在。同样,当一个delegate被回收,您需要删除代表链接通过发送一个消息setDelegate:与一个零参数其他对象。这些消息通常从对象的dealloc方法发送。也就是说,在dealloc方法中,需要把delegate和一起weak references 设为nil。

避免引起回收正在使用的对象。(Avoid Causing Deallocation of Objects You’re Using)

Cocoa’s ownershippolicy specifies that received objects should typically remain valid throughoutthe scope of the calling method. It should also be possible to return areceived object from the current scope without fear of it being released. Itshould not matter to your application that the getter method of an objectreturns a cached instance variable or a computed value. What matters is thatthe object remains valid for the time you need it.

cocoa所有权的政策规定,接收对象通常应该保持在调用方法的整个范围内有效。它还应该有可能返回一个收到对象从当前的范围,而不必担心它被释放。这问题不应你的应用程序对象的getter方法返回一个缓存实例变量或计算值。重要的是这个对象仍然有效,你需要它的时候。

There are occasional exceptions to this rule,primarily falling into one of two categories.

偶有例外,主要落入两类。

1 When an object is removed from one of thefundamental collection classes.

当一个对象被移出你的基本集合类。

heisenObject = [array objectAtIndex:n];
[array removeObjectAtIndex:n];
// heisenObject could now be invalid.

When an object isremoved from one of the fundamental collection classes, it is sent a release(rather than autorelease) message. If the collection was the only owner of theremoved object, the removed object (heisenObject in the example ) is thenimmediately deallocated.

当一个对象被移出你的基本集合类,它发送一个release (而不是autorelease)消息。如果集合是唯一的所有者删除对象,删除对象(在这个例子heisenObject)随后立即销毁。

2 When a “parentobject” is deallocated.

当父对象被销毁

id parent = <#create a parent object#>;
// ...
heisenObject = [parent child] ;
[parent release]; // Or, for example: self.parent = nil;
// heisenObject could now be invalid.

In some situationsyou retrieve an object from another object, and then directly or indirectlyrelease the parent object. If releasing the parent causes it to be deallocated,and the parent was the only owner of the child, then the child (heisenObject inthe example) will be deallocated at the same time (assuming that it is sent arelease rather than an autorelease message in the parent’s dealloc method).

在某些情况下你从另一个对象检索对象,然后直接或间接释放父对象。如果释放父会被收回,并且父是唯一的所有者,那么孩子的孩子(在这个例子heisenObject)将被销毁的同时(假设它是发送一个release,而不是一个autorelease消息在父的dealloc方法)。

To protect againstthese situations, you retain heisenObject upon receiving it and you release itwhen you have finished with it. For example:

为了防止这些情况下,你保留heisenObject收到它和你release它当你完成它。例如:

heisenObject = [[array objectAtIndex:n] retain];
[array removeObjectAtIndex:n];
// Use heisenObject...
[heisenObject release];

不要使用dealloc管理稀缺资源(Don’t Use dealloc to Manage Scarce Resources)

You shouldtypically not manage scarce resources such as file descriptors, networkconnections, and buffers or caches in a dealloc method. In particular, youshould not design classes so that dealloc will be invoked when you think itwill be invoked. Invocation of dealloc might be delayed or sidestepped, eitherbecause of a bug or because of application tear-down.

您通常应该不是管理稀缺资源如文件描述符,网络连接和缓冲区或缓存在dealloc方法。特别是,您不应该设计类,以便将调用dealloc当你认为它将被调用。调用dealloc可能要延迟或回避,要么因为一个bug或因应用程序tear-down。

Instead, if youhave a class whose instances manage scarce resources, you should design yourapplication such that you know when you no longer need the resources and canthen tell the instance to “clean up” at that point. You would typically thenrelease the instance, and dealloc would follow, but you will not sufferadditional problems if it does not.

相反,如果你有一个类的实例管理稀缺资源,你应该设计您的应用程序,这样你知道当你不再需要的资源,然后告诉实例进行“清理”在这一点上。你通常然后释放实例,dealloc将遵循,但你不会遭受额外的问题。

Problems may ariseif you try to piggy-back resource management on top of dealloc. For example:

如果你试图在dealloc方法中管理资源。可以出现如下问题。

1 Order dependencieson object graph tear-down.

依赖的关系图tear-down.

The object graphtear-down mechanism is inherently non-ordered. Although you might typicallyexpect—and get—a particular order, you are introducing fragility. If an objectis unexpectedly autoreleased rather than released for example, the tear-downorder may change, which may lead to unexpected results.

tear-down的对象图机制是固有的非命令。尽管你可能通常期望和得到一个特定的顺序,你的引入是脆弱。如果一个对象是出乎意料的autoreleased而不是released例如, tear-down可能会改变,这可能会导致意想不到的结果。

2 Non-reclamationof scarce resources.

不能回收利用稀缺资源

Memory leaks arebugs that should be fixed, but they are generally not immediately fatal. Ifscarce resources are not released when you expect them to be released, however,you may run into more serious problems. If your application runs out of filedescriptors, for example, the user may not be able to save data.

内存泄漏是错误,应该是固定的,但是他们通常不会立即致命。如果稀缺资源没有release当你希望他们被释放时。然而,你可能会遇到更严重的问题。如果您的应用程序运行的文件描述符,例如,用户可能无法保存数据。

3 Cleanup logicbeing executed on the wrong thread.

清理在错误线程上的逻辑错误。

If an object isautoreleased at an unexpected time, it will be deallocated on whatever thread’sautorelease pool block it happens to be in. This can easily be fatal forresources that should only be touched from one thread.

如果一个对象是autoreleased在一个意想不到的时间,它将被收回在任何线程的生成自动释放池阻止它发生的。这可以很容易地对资源是致命的。

它们包含的对象集合的(Collections Own the Objects They Contain)

When you add anobject to a collection (such as an array, dictionary, or set), the collectiontakes ownership of it. The collection will relinquish ownership when the objectis removed from the collection or when the collection is itself released. Thus,for example, if you want to create an array of numbers you might do either ofthe following:

当你添加一个对象集合(如一个array, dictionary,或set),集合将会持有它。这个集合将会放弃所有权当对象从集合中删除或当收集本身就是释放。因此,例如,如果您想创建一个数字数组,有2种做法。

NSMutableArray *array = <#Get a mutable array#>;
NSUInteger i;
// ...
for (i = 0; i < 10; i++) {
    NSNumber *convenienceNumber = [NSNumber numberWithInteger:i];
    [array addObject:convenienceNumber];
}

In this case, youdidn’t invoke alloc, so there’s no need to call release. There is no need toretain the new numbers (convenienceNumber), since the array will do so.

在这种情况下,您没有调用alloc,所以现在还不需要调用release。没有必要保留新数字(convenienceNumber),因此数组将这样做。

NSMutableArray *array = <#Get a mutable array#>;
NSUInteger i;
// ...
for (i = 0; i < 10; i++) {
    NSNumber *allocedNumber = [[NSNumber alloc] initWithInteger:i];
    [array addObject:allocedNumber];
    [allocedNumber release];
}

In this case, youdo need to send allocedNumber a release message within the scope of the forloop to balance the alloc. Since the array retained the number when it wasadded by addObject:, it will not be deallocated while it’s in the array.

在这种情况下,你需要发送一个release消息allocedNumber范围内的for循环来平衡分配。因为数组保留了数量增加时addObject:,它将不会被收回而它的数组中。

To understandthis, put yourself in the position of the person who implemented the collectionclass. You want to make sure that no objects you’re given to look after disappearout from under you, so you send them a retain message as they’re passed in. Ifthey’re removed, you have to send a balancing release message, and anyremaining objects should be sent a release message during your own deallocmethod.

要理解这一点,把自己的位置的人集合类的实现。你想确保没有对象你给予照顾消失下你,所以你给他们一个保留消息作为他们传递。如果他们移除,你必须发送一个消息,以及任何平衡释放剩余对象应该发送一个发布消息在你自己的dealloc方法。

所有权政策是实现使用保留计数(Ownership Policy Is Implemented Using Retain Counts)

The ownershippolicy is implemented through reference counting—typically called “retaincount” after the retain method. Each object has a retain count.

所有权政策是实现通过引用计数通常称为“保留计数”后保留方法。每一个对象都有一个保持计数。

·      When you create an object, it has aretain count of 1.

创建一个对象时,计数器=1

·      When you send an object a 

retain

 message, itsretain count is incremented by 1.

发送一个retain消息,计数器+1

·      When you send an object a 

release

 message, itsretain count is decremented by 1.

发送release 消息,计数器-1

When you send an object a 

autorelease

 message, itsretain count is decremented by 1 at the end of the current autorelease poolblock.

发送一个autorelease消息,计数器将-1,在autoreleasepool 的最后。

·      If an object’s retain count is reducedto zero, it is deallocated.

当计数器=0,销毁对象所占的内存。