Cocos2d-x 3.1 Memory Management Mechanism

Source: Internet
Author: User

Cocos2d-x 3.1 Memory Management Mechanism

The memory management method used by the Cocos2d-x is reference count, and reference count is a very effective mechanism, by maintaining a reference counter for each object, record the number of times the object is currently referenced. When an object is added with a reference, the counter is added with 1. When an object loses a reference, the counter minus 1. When the reference count is 0, the lifecycle of the object ends, this API automatically triggers the release of an object. The important rule of reference count is that each program segment must maintain the reference count responsibly. The reference count is increased and decreased at the beginning and end of the program segment where the object needs to survive, in this way, you can implement flexible memory management.

Next let's take a look at the Cocos2d-x 3.1 version of the source code is how to implement reference counting.


I. Ref

We all know that almost every class inherits a class Ref. Open CCRef. h to view the Ref class, and remove other variables irrelevant to the reference count, which can be simplified:

// CCRef. hclass CC_DLL Ref {public: void retain (); // reference count plus 1 void release (); // reference count minus 1 Ref * autorelease (); // give the object to the automatically released pool unsigned int getReferenceCount () const; // obtain the current reference count protected: Ref (); // constructor. The permission here is protected, it means that you cannot instantiate the object. Subclass can instantiate public: virtual ~ Ref (); protected: unsigned int _ referenceCount; // reference count: friend class AutoreleasePool; // do not worry about this first };
// CCRef. cppRef: Ref (): _ referenceCount (1) // when an object is new, add 1 {} Ref ::~ Ref () {} void Ref: retain () {CCASSERT (_ referenceCount> 0, "reference count shold greater than 0"); ++ _ referenceCount;} void Ref :: release () {CCASSERT (_ referenceCount> 0, "reference count shocould greater than 0"); -- _ referenceCount; if (_ referenceCount = 0) // when the reference is 0, this object is not called. In this case, the delete object {delete this;} Ref * Ref: autorelease () {PoolManager: getInstance () -> getCurrentPool ()-> addObject (this); // return this to the automatic release pool management;} unsigned int Ref: getReferenceCount () const {return _ referenceCount ;}


To sum up, the Ref class does the following:

1. Ref cannot be instantiated by itself, and can only be instantiated by sub-classes;

2. Create a reference count of 1;

3. Call retain reference count plus 1;

4. Call the release reference count minus 1;

5. Calling autorelease does not reduce the reference count by 1, but is handed over to the automatic release pool for management.


So what is the automatic release pool? It must be related to the PoolManager in the autorelease method.

Open CCAutoreleasePool. two classes are found: AutoreleasePool and PoolManager. Literally, AutoreleasePool is automatically released, and PoolManager is the pool manager. These ideas are clear:

1. After autorelease is called, the object is handed over to AutoreleasePool for management;

2. PoolManager is used to manage AutoreleasePool, indicating that there can be multiple pools.



Ii. AutoreleasePool

Next, let's take a step-by-step look at AutoreleasePool to automatically release the pool and look at the simplified version:

// AutoreleasePool. hclass CC_DLL AutoreleasePool {public: AutoreleasePool (); // Question 1: Create a stack instead of a stack (why? )~ AutoreleasePool (); void addObject (Ref * object); // Add a Ref object to the release pool void clear (); // clear the automatic release pool private: std: vector
 
  
_ ManagedObjectArray; // used to save all the Ref objects added to the Auto Release pool };
 
// AutoreleasePool. cppAutoreleasePool: AutoreleasePool () {_ managedObjectArray. reserve (150); // 1. Set the container size to 150 PoolManager: getInstance ()-> push (this ); // 2. When a new release pool is created, it is added to the release pool manager (which can be put temporarily. Wait until the PoolManager is viewed again)} AutoreleasePool ::~ AutoreleasePool () {clear (); // 1. clear the release pool PoolManager: getInstance ()-> pop (); // 2. Delete the release pool from the release pool manager} void AutoreleasePool: addObject (Ref * object) {_ managedObjectArray. push_back (object); // Add a Ref object to the release pool} void AutoreleasePool: clear () {for (const auto & obj: _ managedObjectArray) // 1. Call the release function of all automatically released objects. Note: delete objects only when the reference count is 0, when the same object is added several times, it will be release several times {obj-> release ();} _ managedObjectArray. clear (); // 2. clear the container}


To sum up, the AutoreleasePool class has done a few things:

1. Maintain a queue for storing the Ref object. These Ref objects will be added to the queue when autorelease is called, and the addObject function is called;

2. The clear function performs a release operation on all the Ref managed by AutoreleasePool. Only when the reference count is 0 will the object be deleted, and several release operations will be executed after several times of addition.


3. PoolManager

PoolManager manages the release pool and uses the push and pop methods in AutoreleasePool. It can be guessed that PoolManager should maintain a stack that stores the release pool:

// PoolManager. h class CC_DLL PoolManager {public: static PoolManager * getInstance (); // PoolManager is a singleton Mode static void destroyInstance (); // Delete the AutoreleasePool * getCurrentPool () const object created in singleton mode; // obtain the current release pool private: PoolManager ();~ PoolManager (); void push (AutoreleasePool * pool); // press a release pool void pop (); // a release pool static PoolManager * s_singleInstance is displayed; std :: deque _ releasePoolStack; // stack AutoreleasePool * _ curReleasePool where the automatic release pool is stored; // The current automatic release pool };
// PoolManager. cpp PoolManager * PoolManager: s_singleInstance = nullptr; // If the singleinstance mode is not created, two release pools are created and added to the PoolManager * PoolManager :: getInstance () {if (s_singleInstance = nullptr) {s_singleInstance = new PoolManager (); // The first pool: the AutoreleasePool constructor adds the constructed pool to the pool manager s_singleInstance-> _ curReleasePool = new AutoreleasePool (); // The second pool: press the new release pool to s_singleInstance-> _ releasePoolStack in the pool manager. push_back (s_sin GleInstance-> _ curReleasePool);} return s_singleInstance;} // The void PoolManager: destroyInstance () {delete s_singleInstance; s_singleInstance = nullptr;} PoolManager :: poolManager () {}// destructor PoolManager ::~ PoolManager () {while (! _ ReleasePoolStack. empty () {AutoreleasePool * pool = _ releasePoolStack. back (); _ releasePoolStack. pop_back (); // 1. The automatic release pool delete pool is displayed; // 2. The delete automatic release pool object} // gets the current release pool AutoreleasePool * PoolManager: getCurrentPool () const {return _ curReleasePool;} void PoolManager: push (AutoreleasePool * pool) {_ releasePoolStack. push_back (pool); // 1. Press the release pool _ curReleasePool = pool; // 2. Set it to the current release pool} // The stack top release pool is displayed, and direct the current release pool to the new stack top release pool void PoolManager: pop () {CC_ASSERT (_ releasePoolStack. size ()> = 1); _ releasePoolStack. pop_back (); if (_ releasePoolStack. size ()> 1) {_ curReleasePool = _ releasePoolStack. back ();}}


It seems that the PoolManager function is simpler, that is, managing the release pool.



Iv. Memory Management Ideas

1. autorelease

When a new object is created, call its autorelease to hand over the object to the Auto Release pool for management.

Ref* Ref::autorelease(){PoolManager::getInstance()->getCurReleasePool()->addObject(this);return this;}

2. PoolManager: getInstance ()

When obtaining the singleton object, if it does not exist, a PoolManager object will be created. At this time, two release pools will be added.



The engine maintains two default release pools. If we do not manually create a release pool, the autorelease object is added to the stack top default release pool.

In fact, I have not understood why there are two default release pools, one of which is also acceptable.


3. getCurReleasePool () obtains the current release pool, and addObject () adds the Ref object to the current release pool. <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHA + PC9wPgo8cHJlIGNsYXNzPQ = "brush: java;"> void AutoreleasePool: addObject (Ref * object) {_ managedObjectArray. push_back (object );}In this way, every Ref object that calls autorelease will be added to _ managedObjectArray.


4. How are objects in the automatic release pool released? View AutoreleasePool: clear () function


Here, loop _ managedObjectArray calls the release of the object in it, calls the release once, reduces the reference count by 1, and deletes the object when the reference count is 0.

You must be wondering where to call the clear function ,~ AutoreleasePool () is called, but it is released during the delete operation. We can see the main loop of the ctor class:


You can see it here. Each primary loop calls clear to release to automatically release the objects in the pool, and each frame executes a primary loop, that is, each frame is cleared once.



5. manually create a release pool

As we know, objects that call the autorelease () method will be released once the pool is released automatically. Although the Cocos2d-x has ensured that the release pool is released once after each frame ends, if a large number of autorelease objects are generated within one frame, performance of the release pool may degrade. Therefore, you can manually create a release pool before and after the areas with intensive autorelease objects (usually in a loop.

{AutoreleasePool pool1; // manually create a release pool for () {ref-> autorelease (); // execute autorelease in the loop. These objects will be added to pool1 }}

At this time, the engine maintains three release pools. We know that the clear () of the current release pool will be executed at the end of each frame (), therefore, the objects above will be released at the end of the first frame, and the autorelease objects placed in the default release pool of the engine will be released at the next frame, with the release time staggered, this will not reduce the performance of the release pool.


When you see the code above, you may wonder why the release pool is created but not released. Do you still remember to note the AutoreleasePool constructor in AutoreleasePool. h: do not create the constructor on the stack, but instead on the stack. We know that the new object must be deleted manually before it can be released, and the variables on the stack will be released when the scope disappears, as shown in pool1 above, when the last "}" is executed, its destructor will be called to see what the AutoreleasePool constructor and destructor have done:

? Success!>? 1) Why cannot I %? Cutting y?>? [In block? Too many tasks? M? Why? Please wait until then !? Why? Why? When a else 0r? I'm just a zombie? Point ky "http://www.bkjia.com/kf/qianduan/css/" target = "_ blank" class = "keylink"> html

3. An implementation of Cocos2d-x Memory Management

4. deep understanding of Cocos2d-x memory management http://www.cocoachina.com/applenews/devnews/2013/0621/6455.html






Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.