天天看點

實際記憶體管理(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,銷毀對象所占的記憶體。