我所理解的Cocos2d-x Cocos2d-x 記憶體管理機制
C++記憶體管理
C++顯式堆記憶體管理
效能上有一定優勢,但有如下缺點:
- 野指標:指標指向的內容已經被釋放,但是其他指標還可能指向它。
- 重複釋放:重複釋放一個已經釋放的記憶體單元,或者釋放一個野指標,都會導致C++執行時錯誤。
- 記憶體洩露:不再被使用的記憶體單元如果不被釋放,就會一直佔用記憶體單元。
C++11智慧指標
主要有如下三種:
- unique_ptr:不能與其他智慧指標共享所指物件的記憶體。一旦轉移成功,就不能使用原來的指標,否則會導致執行時錯誤。
- shared_ptr:共享同一堆分配物件的記憶體,它在實現上採用引用指標。只有引用計數為零時,才會真正釋放佔有的堆記憶體。
- weak_ptr:指向shared_ptr指標分配的物件記憶體,但不擁有該記憶體。我們可以使用其lock成員來訪問其指向記憶體的一個shared_ptr物件,當其所指向的記憶體無效時,返回空值(nullptr)。weak_ptr指標通常可以用來驗證shared_ptr指標的有效性。
為什麼Cocos2d-x不使用智慧指標
有如下理由:
- 智慧指標有較大的效能損失。
- 它需要程式設計師顯示地宣告智慧指標。
- 在需要引用的地方,一般應該使用weak_ptr指標,否則在Node被移除的時候還要手動減持shared_ptr指標的引用計數。
程式設計師每天都面對程式碼,他們需要更自然的記憶體管理方式,就像語言自身的特性一樣,甚至幾乎察覺不到背後的機制。
C++垃圾回收機制
- 基於引用計數:當物件被引用的次數變為零時,該物件即被視作垃圾而被回收。
- 基於跟蹤處理:先產生跟蹤物件的關係圖,再進行垃圾回收。
不管採用哪種方式,垃圾回收機制都可以使記憶體管理變得更自然。
Cocos2d-x記憶體管理
引用計數
Cocos2d-x中的所有物件幾乎都繼承自Ref基類,Ref基類的主要職責就是對物件進行引用計數管理。
- 當一個物件使用new運算子分配記憶體時,引用計數為1。
- 呼叫
retain()
方法會增加其引用計數。 - 呼叫
release()
方法會減少其引用計數。並且在其引用計數為0時自動呼叫delete運算子刪除物件並釋放記憶體。
Ref的引用計數並不是執行緒安全的。在多執行緒中,我們需要通過處理互斥鎖來保證執行緒的安全。
自動回收池(AutoreleasePool)
Cocos2d-x在每一幀結束的時候清理當前AutoreleasePool中的物件,因此可以使用autorelease()
方法來宣告一個物件指標加入AutoreleasePool。
為了化簡這種宣告,Cocos2d-x使用靜態的
create()
方法來呼叫加入AutoreleasePool。同時,自定義的UI元素也應該遵循這樣的風格。
AutoreleasePool佇列
對於一些遊戲物件而言,一幀的生命週期有些長。我們需要能夠自定義AutoreleasePool的生命周長。AutoreleasePool在建構函式中將自身指標新增到PoolManager的AutoreleasePool佇列中,並在解構函式中從佇列中移除自己。通過在函式開頭定義AutoreleasePool物件,就能控制Cocos2d-x中的autorelease物件的宣告週期了。
不要動態分配AutoreleasePool物件,而始終使用自動變數。
Cocos2d-x中的智慧指標
Cocos2d-x 3.1 引入了智慧指標RefPtr<T>
,是基於RAII實現的。
建構函式
RefPtr需要依賴Ref的引用計數來管理記憶體,因此所有型別T必須是Ref型別。- 對於使用左值作為建構函式的引數,會使得引用計數加1。
- 而使用右值作為建構函式的引數,不會使得引用計數加1。而是使用了移動複製建構函式,將其對應的記憶體佔用轉移過來。
賦值操作符
- 對於使用左值來賦值,會使得引用計數加1。
- 而使用右值來賦值,不會使得引用計數加1。而是使用了移動複製建構函式,將其對應的記憶體佔用轉移過來。不過,有一點不同的是會釋放之前舊的資源的引用計數。
弱引用賦值
RefPtr通過提供一個
weakAssign()
方法來實現弱引用。
但是在析構的時候,依然會release()
一次。
有什麼用呢?示例如下:void a() { RefPtr<Texture2D> l; l.weakAssign(new Texture2D); // -- doSomething return; }
在函式中並沒有delete,但是依舊不會造成記憶體洩露。
解構函式:對_ptr進行safe delete。
過載了“*”和“->”操作符,使得其能夠直接訪問資源的地址。另外也可以通過
get()
方法來訪問資源的地址。RefPtr也過載了
bool()
操作符,使我們可以直接判斷其有效性。
- Cocos2d-x自動回收池和智慧指標該用誰?
作者的建議是,所有的UI元素都需要使用autorelease來管理,而遊戲中的資料則使用智慧智慧RefPtr來管理。- RefPtr的缺陷
- 可以從外部修改引用計數。
- 雖然RefPtr提供了一種弱引用,不對其進行引用計數增加,但仍然表現為一個強型別智慧指標的行為,它仍然可以對其資源進行修改。