iOS开发内存管理总结
生活随笔
收集整理的這篇文章主要介紹了
iOS开发内存管理总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、retain、copy、assign的區別:1.retain:當對一個對象A調用retain,然后賦值給B時,對象的引用計數加1,A和B指向同一個內存地址。2.copy:當對一個對象A調用retain,然后賦值給B時,對象的引用計數加1,而且生成了一個新的拷貝,A和B指向不一樣的內存地址。3.assign:當對一個對象A調用retain,然后賦值給B時,對象的引用計數不變,A和B指向同一個地址。
二、為什么delegate聲明要使用assign?因為如果使用assign的話,對象間會產生循環引用的情況,導致循環引用的對象都不能釋放內存。
三、atomic和noatomic的區別這兩個關鍵字用來決定編譯生成的getter和setter方法是否為原子操作,即是否是多線程安全的。atomic表示是原子操作,支持多線程安全,noatomic是非原子操作,不支持多線程安全。
四、自動釋放池1.自動釋放池實現了對象的延遲釋放,將釋放時機延后。當對一個對象調用autorelease方法后,對象被加入自動釋放池。當自動釋放池釋放時,會對自動釋放池中的對象調用release方法。2.主線程會自動創建自動釋放池,自己創建的線程需要自己負責創建自動釋放池。在一個RunLoop周期開始時,系統會創建一個自動釋放池,當RunLoop周期結束時,系統會釋放之前創建的自動釋放池。如果我們在使用autorelease時沒有自己創建自動釋放池,對象會在它所在的RunLoop周期結束時被釋放掉。一個UI事件,Timer調用,delegate調用,都會是一個新的Runloop。3.類似于[NSString stringWithFormat:]這樣的類方法創建的對象默認是使用了自動釋放池的,不需要釋放。4.當在短時間內大量的使用自動釋放對象,要手動使用自動釋放池來釋放對象,否則內存會在短時間內瘋漲。
六、didReceiveMemoryWarning、viewDidUnload和dealloc方法使用1.didReceiveMemoryWarning方法:首先調用[super didReceiveMemoryWarning]方法,然后檢查當前視圖的父視圖是否為空,如果為空,則釋放掉一些不需要的數據。關于視圖界面的釋放不應該在這個方法中,應該放在viewDidUnload方法中。2.viewDidUnload方法:(1)此方法只在發生內存警告時調用。在這個方法調用之前,控制器的view屬性已經被release并且設置為nil。(2)iOS6之前:當低內存情況發生,而且當前視圖不需要顯示時,系統會調用此方法來清理額外的視圖(但是控制器還存在)。在此方法中我們需要清理輸出口,比如清理輸出口:self.xxxx = nil;(使用self關鍵字);以及我們自己通過代碼建立的視圖界面。我們不應該在此方法中清除數據,尤其是一些不能恢復的數據。可以恢復的數據我們應該在didReceiveMemoryWarning中清除,不能恢復的數據應該在dealloc方法中清除。(3)iOS6以及之后:當控制器的視圖已經沒有顯示在window上時,系統會自動清空控制器中的所有視圖以及輸出口,所以不用在發生內存警告時再調用此方法。所以,在iOS6以及以后的版本,這個方法不會再被調用了。3.dealloc方法:對象釋放時調用,在這個方法中,要釋放掉所有的數據和輸出口。比如釋放輸出口:[xxx release];(不使用self關鍵字)
六、一些注意的地方1.向集合(NSArray,NSDictionary等)添加對象時,被添加的對象會被執行retain操作,當從集合中移走對象或者集合對象被釋放時,集合中的對象會被執行release操作。2.要保證有多少個alloc、copy、multablecopy、retain消息,就要有多少個release或者autorelease,保證代碼平衡。3.在程序中直接用@""創建的NSString對象,是常量,引用計數是-1,向它發送retain、release沒有效果。4.在View中使用圖片時,大的圖片區域盡量使用小的圖片數據來填充,減小內存占用。5.[UIImage imageNamed:@""],次方法使用了系統緩存來緩存圖像,會長時間占用內存,最好使用imageWithContentsOfFile方法。6.數據要延遲加載,只在內存中保留滿足需要的最少的數據和視圖元素,需要的時候再加載,不需要就馬上銷毀。7.假如一個成員變量在property中使用了retain,當使用self關鍵字對其賦值時,會對創建的對象再retain一次,造成內存泄露。比如:self.xxx = [[XXX alloc] init];? 對一個成員變量賦nil值時,self.xxx = nil,會調用xxx的release方法,并且將指針置空,xxx = nil,只是將指針置空。8.加載本地圖片時,盡量不要使用[UIImage imageNamed:@""]這個方法,因為這個方法會使用系統緩存來緩存圖像,會占用內存。可以使用[UIImage imageWithContentOfFile:@""]來加載本地圖像。9.在控制器中使用NSTimer會使當前控制器引用計數加1,所以在控制器釋放之前,必須暫停和使定時器失效,否則控制器將不會被釋放。
七、內存警告(iOS6之前)1.原理:當發生內存警告時,系統會對程序內存在的所有的ViewController調用didReceiveMemoryWarning方法,然后,如果當前ViewController沒有父視圖(即沒有顯示),viewDidUnload方法會被調用(iOS6及以后不調用)。之后,當ViewController的視圖對象,比如view,被再次訪問時,viewDidLoad方法會被調用,一般視圖初始化和數據創建都在viewDidLoad方法里面做,所以界面和數據會恢復。2.處理方法:(1)使用數據緩存機制:為每個ViewController創建一個數據緩存池,比如使用NSMultableDictionary類型,我們把所有可以重建的數據、動態創建的視圖元素引用都保存在這個緩存池中,而且每組數據都用一個Key對應。如果緩存池中已經存在這組數據了,則直接取出來用,如果不存在,則創建再使用。(2)當發生內存警告時,如果當前視圖在顯示,則只清空數據,不清空視圖元素引用,如果不在顯示,則把數據和視圖元素引用都清空。(3)發生內存警告后,當控制器的視圖重新回到window顯示時,viewDidLoad方法會被調用,界面和數據會恢復。(4)當控制器銷毀時,在delloc方法中將數據緩存中的數據全部清空。(5)當需要重置緩存中的數據時,按照Key從緩存池中刪除對應的數據,然后再按照第(1)條的規則取數據。3.遇到的問題:蘋果推薦的didReceiveMemoryWarning的實現方式是這樣:-----------------------------------------------------------(void)didReceiveMemoryWarning{? ? if (self.view.superview == nil) {? ? ? ? ? ? //在此處清空一些不需要的數據? ? ? ? }? ? [super didReceiveMemoryWarning];}----------------------------------------------------------假如此時這個視圖控制發生了內存警告,數據和視圖元素被釋放了,然后在這個視圖恢復顯示之前,又發生了內存警告,就再次調用了此方法,因為在這個方法中訪問了view屬性,所以viewDidLoad方法會調用,視圖和數據被重建,創建完之后,視圖和數據又馬上被清空。這個過程時多余的。4.解決辦法:在控制器中設立一個變量,用來標志是否需要對內存警告做出響應,比如,isNeedCheckMemoryWarning,在viewDidLoad方法中將其設置為YES,在didReceiveMemoryWarning方法中檢查這個值,代碼如下:-----------------------------------------------------------(void)didReceiveMemoryWarning{? ? if (isNeedCheckMemoryWarning == YES && self.view.superview == nil) {? ? ? ? //在此處清空一些不需要的數據? ? }? ? isNeedCheckMemoryWarning = NO;? ? [super didReceiveMemoryWarning];}
八、內存警告(iOS6之后)1.不同之處:(1)iOS6之后viewDidUnload不再調用,當控制器的視圖已經沒有顯示在window上時,系統會自動清空控制器中的所有視圖以及輸出口。(2)因為視圖的釋放由系統控制了,所以當發生內存警告之后,view被再次訪問,viewDidLoad不再調用。(3)綜合以上兩點,所有關于界面的回收和恢復我們都可以不用管,包含動態創建的視圖(可以恢復)。我們只需要關注數據。
2.處理方法與第七點的不同<1>同樣使用數據緩存池,但是數據緩存池中只存儲視圖之外的數據。<2>數據緩存池的創建放到initXXX方法中,只創建一次。<3>第三點遇到的問題不存在了,可以不用加isNeedCheckMemoryWarning變量。
二、為什么delegate聲明要使用assign?因為如果使用assign的話,對象間會產生循環引用的情況,導致循環引用的對象都不能釋放內存。
三、atomic和noatomic的區別這兩個關鍵字用來決定編譯生成的getter和setter方法是否為原子操作,即是否是多線程安全的。atomic表示是原子操作,支持多線程安全,noatomic是非原子操作,不支持多線程安全。
四、自動釋放池1.自動釋放池實現了對象的延遲釋放,將釋放時機延后。當對一個對象調用autorelease方法后,對象被加入自動釋放池。當自動釋放池釋放時,會對自動釋放池中的對象調用release方法。2.主線程會自動創建自動釋放池,自己創建的線程需要自己負責創建自動釋放池。在一個RunLoop周期開始時,系統會創建一個自動釋放池,當RunLoop周期結束時,系統會釋放之前創建的自動釋放池。如果我們在使用autorelease時沒有自己創建自動釋放池,對象會在它所在的RunLoop周期結束時被釋放掉。一個UI事件,Timer調用,delegate調用,都會是一個新的Runloop。3.類似于[NSString stringWithFormat:]這樣的類方法創建的對象默認是使用了自動釋放池的,不需要釋放。4.當在短時間內大量的使用自動釋放對象,要手動使用自動釋放池來釋放對象,否則內存會在短時間內瘋漲。
六、didReceiveMemoryWarning、viewDidUnload和dealloc方法使用1.didReceiveMemoryWarning方法:首先調用[super didReceiveMemoryWarning]方法,然后檢查當前視圖的父視圖是否為空,如果為空,則釋放掉一些不需要的數據。關于視圖界面的釋放不應該在這個方法中,應該放在viewDidUnload方法中。2.viewDidUnload方法:(1)此方法只在發生內存警告時調用。在這個方法調用之前,控制器的view屬性已經被release并且設置為nil。(2)iOS6之前:當低內存情況發生,而且當前視圖不需要顯示時,系統會調用此方法來清理額外的視圖(但是控制器還存在)。在此方法中我們需要清理輸出口,比如清理輸出口:self.xxxx = nil;(使用self關鍵字);以及我們自己通過代碼建立的視圖界面。我們不應該在此方法中清除數據,尤其是一些不能恢復的數據。可以恢復的數據我們應該在didReceiveMemoryWarning中清除,不能恢復的數據應該在dealloc方法中清除。(3)iOS6以及之后:當控制器的視圖已經沒有顯示在window上時,系統會自動清空控制器中的所有視圖以及輸出口,所以不用在發生內存警告時再調用此方法。所以,在iOS6以及以后的版本,這個方法不會再被調用了。3.dealloc方法:對象釋放時調用,在這個方法中,要釋放掉所有的數據和輸出口。比如釋放輸出口:[xxx release];(不使用self關鍵字)
六、一些注意的地方1.向集合(NSArray,NSDictionary等)添加對象時,被添加的對象會被執行retain操作,當從集合中移走對象或者集合對象被釋放時,集合中的對象會被執行release操作。2.要保證有多少個alloc、copy、multablecopy、retain消息,就要有多少個release或者autorelease,保證代碼平衡。3.在程序中直接用@""創建的NSString對象,是常量,引用計數是-1,向它發送retain、release沒有效果。4.在View中使用圖片時,大的圖片區域盡量使用小的圖片數據來填充,減小內存占用。5.[UIImage imageNamed:@""],次方法使用了系統緩存來緩存圖像,會長時間占用內存,最好使用imageWithContentsOfFile方法。6.數據要延遲加載,只在內存中保留滿足需要的最少的數據和視圖元素,需要的時候再加載,不需要就馬上銷毀。7.假如一個成員變量在property中使用了retain,當使用self關鍵字對其賦值時,會對創建的對象再retain一次,造成內存泄露。比如:self.xxx = [[XXX alloc] init];? 對一個成員變量賦nil值時,self.xxx = nil,會調用xxx的release方法,并且將指針置空,xxx = nil,只是將指針置空。8.加載本地圖片時,盡量不要使用[UIImage imageNamed:@""]這個方法,因為這個方法會使用系統緩存來緩存圖像,會占用內存。可以使用[UIImage imageWithContentOfFile:@""]來加載本地圖像。9.在控制器中使用NSTimer會使當前控制器引用計數加1,所以在控制器釋放之前,必須暫停和使定時器失效,否則控制器將不會被釋放。
七、內存警告(iOS6之前)1.原理:當發生內存警告時,系統會對程序內存在的所有的ViewController調用didReceiveMemoryWarning方法,然后,如果當前ViewController沒有父視圖(即沒有顯示),viewDidUnload方法會被調用(iOS6及以后不調用)。之后,當ViewController的視圖對象,比如view,被再次訪問時,viewDidLoad方法會被調用,一般視圖初始化和數據創建都在viewDidLoad方法里面做,所以界面和數據會恢復。2.處理方法:(1)使用數據緩存機制:為每個ViewController創建一個數據緩存池,比如使用NSMultableDictionary類型,我們把所有可以重建的數據、動態創建的視圖元素引用都保存在這個緩存池中,而且每組數據都用一個Key對應。如果緩存池中已經存在這組數據了,則直接取出來用,如果不存在,則創建再使用。(2)當發生內存警告時,如果當前視圖在顯示,則只清空數據,不清空視圖元素引用,如果不在顯示,則把數據和視圖元素引用都清空。(3)發生內存警告后,當控制器的視圖重新回到window顯示時,viewDidLoad方法會被調用,界面和數據會恢復。(4)當控制器銷毀時,在delloc方法中將數據緩存中的數據全部清空。(5)當需要重置緩存中的數據時,按照Key從緩存池中刪除對應的數據,然后再按照第(1)條的規則取數據。3.遇到的問題:蘋果推薦的didReceiveMemoryWarning的實現方式是這樣:-----------------------------------------------------------(void)didReceiveMemoryWarning{? ? if (self.view.superview == nil) {? ? ? ? ? ? //在此處清空一些不需要的數據? ? ? ? }? ? [super didReceiveMemoryWarning];}----------------------------------------------------------假如此時這個視圖控制發生了內存警告,數據和視圖元素被釋放了,然后在這個視圖恢復顯示之前,又發生了內存警告,就再次調用了此方法,因為在這個方法中訪問了view屬性,所以viewDidLoad方法會調用,視圖和數據被重建,創建完之后,視圖和數據又馬上被清空。這個過程時多余的。4.解決辦法:在控制器中設立一個變量,用來標志是否需要對內存警告做出響應,比如,isNeedCheckMemoryWarning,在viewDidLoad方法中將其設置為YES,在didReceiveMemoryWarning方法中檢查這個值,代碼如下:-----------------------------------------------------------(void)didReceiveMemoryWarning{? ? if (isNeedCheckMemoryWarning == YES && self.view.superview == nil) {? ? ? ? //在此處清空一些不需要的數據? ? }? ? isNeedCheckMemoryWarning = NO;? ? [super didReceiveMemoryWarning];}
八、內存警告(iOS6之后)1.不同之處:(1)iOS6之后viewDidUnload不再調用,當控制器的視圖已經沒有顯示在window上時,系統會自動清空控制器中的所有視圖以及輸出口。(2)因為視圖的釋放由系統控制了,所以當發生內存警告之后,view被再次訪問,viewDidLoad不再調用。(3)綜合以上兩點,所有關于界面的回收和恢復我們都可以不用管,包含動態創建的視圖(可以恢復)。我們只需要關注數據。
2.處理方法與第七點的不同<1>同樣使用數據緩存池,但是數據緩存池中只存儲視圖之外的數據。<2>數據緩存池的創建放到initXXX方法中,只創建一次。<3>第三點遇到的問題不存在了,可以不用加isNeedCheckMemoryWarning變量。
總結
以上是生活随笔為你收集整理的iOS开发内存管理总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GCD简介四:挂起,目标指定,信号量
- 下一篇: 战地体能训练模拟器