程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 《C#妹妹和Objective-C阿姨對話錄》(04)垃圾回收基礎--拆遷隊那點事

《C#妹妹和Objective-C阿姨對話錄》(04)垃圾回收基礎--拆遷隊那點事

編輯:C#入門知識

C#妹妹:操作系統天天說控制內存空間價格,咋還這麼高?我巨資購買的內存空間,後來發現竟然在硬盤上!虛擬內存!TMD!

Objective-C阿姨:操作系統全靠賣內存空間掙錢呢,你說價格能會降麼?你看看那些程序員心理就平衡了,上海買房子結果買到江蘇,北京買房子結果買到河北,上班還要跨省,天天面向對象,到頭來連個對象都找不到。。

C#妹妹:靠,還是那句話“同一個世界 同一個噩夢”,你說內存空間賣光了咋辦?

Objective-C阿姨:把你內存空間回收了再賣給別人呗。

C#妹妹:啊??!!人家在用的內存也回收啊?

Objective-C阿姨:廢話,所有的內存都是操作系統的,只是借給你而已,操作系統讓你強制退出,你有辦法哇,把你干掉然後發個新聞稿,說“死者目前情緒穩定”就好了。,不信看看你的《內存空間證》上使用期限是多少?

C#妹妹:60ms?! 真TMD的!這麼霸道,剛出台的《內存權法》就不管麼?。

Objective-C阿姨:操作系統執行的是1949年制定的《垃圾回收暫行條例》,已經暫行60多年了⋯⋯再說維穩是一切工作的核心!聽操作系統的話,讓你賣空間就買,讓你租就租,讓你釋放空間就釋放。特別是不用的對象趕快釋放掉。操作系統最討厭占茅坑不拉屎,輕則強制釋放,重則刪除程序,屍骨無存。。

C#妹妹:還好,我們.NET程序請了個拆遷隊“垃圾回收器”,專門干這個事情。發現有用不到的對象,就主動還給操作系統了,早點把內存交給操作系統,興許給我的補償內存地段好點,別在給我安排什麼虛擬內存了,再說操作系統請的強制拆遷隊比較野蠻,盡量不麻煩他們了。

Objective-C阿姨:呵呵,這是個好主意,不過.NET的垃圾回收器咋知道你用不到這些對象?會不會把正用的對象也拆遷了?

C#妹妹:所謂用不到,就是指代碼裡沒有再引用這些對象,.NET的所有對象都是由局部變量, 全局變量, 靜態變量, 指向托管堆的CPU寄存器,直接或者間接引用的,所以他們稱之為“根”,垃圾回收器只需要從根出發,掃描這些根都引用了那些對象,並且全部記錄下來,余下那些沒有記錄在冊的對象就都可以回收了。拆除都是垃圾回收器自動進行的,程序員一般不用干預了,復雜些的對象程序員要在方法Finalize()裡留下拆除方法,垃圾回收器拆除非托管資源還不太在行,還是需要程序員指點一下的。這個過程非常安全,正在使用的對象是不會被回收的。

Objective-C阿姨:垃圾回收器咋知道對象間的引用關系的?

C#妹妹:通過元數據啊,元數據描述了對象間的引用關系,並且.NET是類型安全的,對象指針只能指向相應的對象。

C#妹妹:Objective-C阿姨,您的內存是如何管理的?

Objective-C阿姨:Objective-C 2.0也是有垃圾回收機制的,但是只能在Mac OS X Leopard 以上的版本使用。

C#妹妹:Leopard?豹子?是個什麼概念?

Objective-C阿姨:這個要從Mac的版本說起,Mac OS X各個版本都是些貓科動物啦,現在最新版本是Snow Leopard,今年夏天Lion可能會發布。

下面的圖大概描述了Mac OS X的歷史。

 

哪像你們東家MS那麼沒有創意,今年一個窗戶,明年一個窗戶的造;天天造窗戶,哪有不碎玻璃的,這不三月底MS亞太研究中心大樓有玻璃掉下來了。

C#妹妹: ,還是繼續說垃圾回收的事情好哇。。。

Objective-C阿姨:好吧,不批你們東家了。接著說,iPhone和iPad開發也是不支持垃圾回收的。

C#妹妹:內存就需要程序員主動釋放是麼?

Objective-C阿姨:沒錯,不過Cocoa已經進行了簡化,看下面的例子吧。

首先要建立個被測試銷毀的對象

#import "House.h"
//先建一個需要被刪除的對象 House類
@implementation House
-(void) dealloc//Objective-C在銷毀對象的時候會自動調用這個方法
{
    NSLog(@"房子被拆除了");
    [super dealloc];
}
@end
這個House類是空的,裡邊只有個dealloc方法,能在拆除的時候顯示一條信息“房子被拆除了”。

C#妹妹:好杯具的房子

Objective-C阿姨:下面的程序調用這個House對象

    House *h1=[House new];
    NSLog(@"A.對象引用數量:%lu",[h1 retainCount]);
    [h1 retain];
    NSLog(@"B.對象引用數量:%lu",[h1 retainCount]);
    [h1 release];
    NSLog(@"C.對象引用數量:%lu",[h1 retainCount]);
    [h1 release ];


先說[h1 retainCount]表示由多少個地方引用這個h1實例(House的實例),但是這個統計是否准確跟系統關系不大,主要看程序員統計的是否准確。

Objective-C使用的是引用計數的方式來檢測對象是否需要回收的,通過new、alloc創建的對象,計數器都是1。位置A對象剛被new實例話,所以引用數量是1;

如果這個對象被其他對象引用一次 調用一次 retain,引用的數量加1。位置B剛調用了retain,所以引用數量加1,所以顯示2。

如果引用的某個對象釋放該對象,調用一次release,引用的數量減1。位置C剛調用了release,所以引用數量減1,所以顯示1。

最後又調用了一次release,這個時候這個實例的引用數量為0,說明這個實例已經不再使用了,Objective-C會自動調用該對象的dealloc方法,回收資源。所以顯示了“房子被拆除了”~

與.NET的區別在於,.NET是垃圾回收器自動統計那些對象已經沒有引用了,但是這個工作在Objective-C上,必須由程序員來完成。


上面的例子純粹為了展示retain、release、retainCount,程序員強制通過 retain、release改變引用數量的統計值(引用數量當然沒有改變),實際操作是肯定不會這樣進行的。

看下面這個稍微實戰一點的例子

    House *h1=[House new];//new後有一個引用
    House *h2;
    House *h3;
    NSLog(@"%lu",[h1 retainCount]);//返回1
   
    h2=h1;//h2也引用到這個對象上
    [h1 retain];//所以手動更新引用計數器 為2
    NSLog(@"%lu,%lu",[h1 retainCount],[h2 retainCount]);//返回2,2
   
    h3=h2;//h3也跑過來湊熱鬧,這個時候對象有3個引用了
    [h1 retain];//所以手動更新引用計數器 為3
    NSLog(@"%lu,%lu,%lu",[h1 retainCount],[h2 retainCount],[h3 retainCount]);//返回3,3,3
   
    h1=nil;//h1不再引用對象
    [h3 release];//計數器減1
    NSLog(@"%lu,%lu,%lu",[h1 retainCount],[h2 retainCount],[h3 retainCount]);//返回0,2,2
   
    h2=nil;//h2也不再引用對象
    [h3 release];//計數器減1
    NSLog(@"%lu,%lu,%lu",[h1 retainCount],[h2 retainCount],[h3 retainCount]);//0,0,1
   
    [h3 release];//計數減為0,表示該對象已經沒有引用了,拆遷隊一湧而上,回收對象的內存,並返回“房子被拆除了”
C#妹妹:基本看明白了,h1h2h3 三個變量折騰了半天,其實都是指向一個實例,不斷的通過retain和release同步對象的引用數量,一旦引用數量為0(不是真正的引用數量,是程序員統計出來的引用數量為0),拆遷隊就上去拆房子,對麼?所以程序員統計對象引用的工作非常重要。而在.NET中,判斷引用為0的工作是由垃圾回收器完成的。

Objective-C阿姨:是的,Objective-C就是這樣管理內存的,不過這只是剛剛開始,下次有更復雜的例子和更簡潔的方法


小墨的童鞋

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved