cocos2dx原始碼分析之記憶體管理

2021-07-12 00:54:08 字數 2955 閱讀 9884

在cocos2dx框架中,我們似乎有一種感覺–不用手動釋放記憶體,其實,這些都是框架幫我們實現好的

cocos2dx中採用了一種比較古老的方式—–引用計數的方式來實現記憶體的自動**,如果是了解c++11中的std::shared_ptr的同學肯定不會覺得陌生,原理是類似的。

我們首先來明確乙個問題,cocos2dx是在什麼地方釋放記憶體的呢?

我們來看原始碼:

ccdirector.cpp

//簡化版

void displaylinkdirector::mainloop()

這個是cocos2dx的主迴圈,我們不難看出,在每一幀繪製結束後,poolmanager就會進行乙個clear()操作,這裡,就是我們cocos2dx記憶體管理的入口了

那麼這個poolmanager又是怎麼實現的呢?

這個就要從我們ref類講起了

class cc_dll ref

根據我們上面主迴圈的**poolmanager應該是實現記憶體自動釋放的關鍵

class cc_dll poolmanager

...autoreleasepool* poolmanager::getcurrentpool() const

這是乙個單例類,其中呼叫的getcurrentpool方法返回的只是乙個autoreleasepool的向量

並且這個autoreleasepool是他的友緣類,而且也是ref的友緣類

我們來看看autoreleasepool的實現

class cc_dll autoreleasepool

void autoreleasepool::clear()

...}

ref::relase的實現

void ref::release()

...}

大體上就是這樣乙個流程

那麼如何保留我們的例項不被釋放呢?

很簡單,使用我們的retain方法,其實就是將引用計數加一

void ref::retain()

因為每次進行clear()的時候,會把_managedobjectarray清空

也就是說,每個繼承自ref的類例項化後只會進行一次release,所以我們呼叫retain將引用計數加一後就不用擔心被釋放的問題了

那麼reatin後的例項如何釋放呢?

也很簡單, 呼叫autorelease或者release即可

ref* ref::autorelease()

void

autoreleasepool::addobject(ref* object)

autorelease會將當前例項加入到待釋放陣列中,所以就可以實現自動釋放了

還有乙個問題,既然是引用計數,那麼最開始的引用數是在**賦值的呢?

是在ref的建構函式中

ref::ref()

: _referencecount(1) // when the ref is created, the reference count of it is 1

...

所以,我們在cocos2dx開發中,一般使用框架中的vector因為vectorpushback()的時候,會呼叫一次retain官方文件上的一些話:

ccautoreleasepool不能被開發者自己建立。cocos2d-x會為我們每乙個遊戲建立乙個自動釋放池例項物件,遊戲開發者不能新建自動釋放池,僅僅需要專注於release/retain cocos2d::ccobject的物件。

ccautoreleasepool不能被用在多執行緒中,所以假如你遊戲需要網路執行緒,請僅僅在網路執行緒中接收資料,改變狀態標誌,不要這個執行緒裡面呼叫cocos2d介面。下面就是原因:

ccautoreleasepool的邏輯是,當你呼叫object->autorelease(),object就被放到自動釋放池中。自動釋放池能夠幫助你保持這個object的生命週期,直到當前訊息迴圈的結束。在這個訊息迴圈的最後,假如這個object沒有被其他類或容器retain過,那麼它將自動釋放掉。例如,layer->addchild(sprite),這個sprite增加到這個layer的子節點列表中,他的宣告週期就會持續到這個layer釋放的時候,而不會在當前訊息迴圈的最後被釋放掉。

這就是為什麼你不能在網路線層中管理ccobject生命週期,因為在每乙個ui執行緒的最後 ,自動釋放物件將會被刪除,所以當你呼叫這些被刪掉的物件的時候,你就會遇到crash。

簡而言之,這只有兩種情況你需要呼叫release()方法

你new乙個cocos2d::ccobject子類的物件,例如ccsprite,cclayer等。

你得到cocos2d::ccobject子類物件的指標,然後在你的**中呼叫過retain方法。

cocos2d x 原始碼剖析(2)

上次講到cocos2d x的main loop是下面這句 我們來看看這個函式的內部實現 return0 看看,我沒有欺騙大家吧。這個函式在設計的時候想要參照main函式返回乙個int值來表示執行結果,但是你知道的外部呼叫中完全沒有進行處理,略坑爹。來深入這個函式的內部 void startmainl...

cocos2d x 原始碼剖析(1)

原文出處 我認為在看這些文章的時候,最好有一些cocos2d x的經驗。起碼能新建乙個cocos2d x的hello world工程。而且這些文章並不是用來入門和教你如何使用cocos2d x的,我的目標是看完這些文章之後,寫乙個完整的2d引擎將沒有問題。而且能夠為cocos2d x查漏補缺,看看那...

cocos2d x 原始碼剖析(8)

寫到第7節的時候,突然覺得cocos2d x還沒有我想的那麼大啊,或許在50節以內就要了結了。這節繼續看看ccnode這個節點,主要部分是action。雖然ccnode有不少的action相關的函式,起作用的實際上是actionmanager。這節雖說是從ccnode開始,但是真正的內容在actio...