First, we must talk about the memory space allocation of variables in C ++. We should write a class in C ++, you can allocate memory space on the stack or use new to allocate memory space on the stack. If the class object is the memory space allocated on the stack, the management of this memory space is not our problem, but if it is the memory space allocated on the stack, of course we need to manually delete it! Cocos2dx is used to allocate memory space on the stack. Think about whether most of the classes in cocos2dx are obtained through the factory method during program writing, have you ever seen memory space allocation on the stack? So the problem arises. Since the memory space is allocated on the stack, it is a problem to manage the memory space and when to release it! In the program, when we create an object, this memory space is often referenced by different objects. If it is deleted earlier, if an object still references this memory space, the program will inevitably crash! Therefore, cocos2dx introduces the memory management mechanism of reference count.
When we allocate a memory space on the heap, the reference count of this object is 1. When an object wants to reference this memory space, this reference count increases by 1, when an object no longer references this memory, the reference count is reduced by 1. When the reference count is reduced to 0, delete the memory, in this way, the memory will be accessed normally when an object is referenced, and the reference can be recycled normally. Let's take a look at the following code to find out the reference count!
// When an object is created, the reference count is set to 1, which is completed in its constructor, it will first call the constructor of the parent class ccojbect // The constructor of ccobject is as follows // ccobject: ccobject (void) //, m_ureference (1) {} // when the object is created, the reference count of it is 1 ccsprite * sprite = new ccsprite (); cclog ("retain count: % d ", sprite-> retaincount (); // when the retain method is called, the reference count increases by 1 sprite-> retain (); cclog ("retain count: % d ", sprite-> retaincount (); // when the release method is called, the reference count is reduced by one. When the reference count is reduced to 0, in the release method, the object sprite-> release (); cclog ("retain count: % d", Sprite-> retaincount () will be deleted ()); // this code will be called when we call the autorelease method // ccpoolmanager: sharedpoolmanager ()-> addobject (this ); // when the autorelease method is called, the object is placed in the automatic recycle pool. The automatic recycle pool calls the release method sprite-> autorelease () of the object at the end of each frame (); cclog ("retain count: % d", Sprite-> retaincount ());
The above Code does not have a good understanding, that is, the automatic recovery mechanism that we often call, that is, the autorelease method above. What does this method do for us and what is its function, we need to figure it out! First, we need to clarify the concept of frame. We often say how many frames per second. In fact, the amount of time required for this frame is not fixed. It depends on how much we need to do for each frame, if there is no frame, we need to render a lot of things, then the execution time of this frame will certainly be very long, and the game will become very stuck, at this time, the frame rate per second will decrease, so it is not the frame rate determined by time, but the time of frame impact! This automatic recycle pool works at the end of each frame. Each frame of the game has a large loop. Before a frame starts, the system creates a memory recycle pool, during this frame process, when we call the autorelease method, our objects will be placed in this memory recycle pool, when a frame ends, the memory recycle pool will be released, and objects in the memory recycle pool will be release, that is, the reference count will be reduced by one, if the reference count is 0 at this time, the object will be deleted. If the reference count is not 0, the object will not be deleted. At the beginning of the next frame, the system will create a memory recycle pool, at this time, the last added object will not be added to the memory recycle pool again, the objects in the memory recycle pool are the objects you have called the autorelease function in this frame. Okay, I think I have already made it clear about the memory recycle pool. Next, let's take a look at how our code is usually written. Let's take a look at how this Automatic Recovery Mechanism achieves automatic recovery!
// The sprite autorelease method ccsprite * sprite = ccsprite: Create ("helloworld.png"); cclog ("retain count: % d ", sprite-> retaincount (); // retain 1this-> addchild (sprite); cclog ("retain count: % d", Sprite-> retaincount ()); // retain 2
First, we need to analyze the above Code. After the create factory method is called, the internal implementation is to first create a ccsprite object. At this time, the reference count is added to 1, and then the autorelease method is called, put this object in the automatic recycle pool, because this frame is not over yet, of course, the reference count is still 1, so the printed result is 1. When we call addchild, pass in this ccsprite object. When the current layer accepts this object, it will add a reference count plus one, indicating that the current layer is using this memory space, so the current retain is 2. When this frame ends, the automatic recycle pool will count the reference of the object-1, so now only the cclayer references this object. When the cclayer destructor, it will call the release method of this object, and of course this ccsprite object will be deleted. So what is the automatic recovery mechanism? automatic means that at the end of the frame, the reference count added when the object is new is reduced, let other classes in the engine hold object references to manage this object. When the owner analyzes the structure, the reference will be deleted. The classes in the engine are responsible for retain and release. This is also automatic! The following two examples illustrate the memory management mechanism.
Bool helloworld: Init () {If (! Cclayer: Init () {return false;} ccmenuitemimage * pcloseitem = ccmenuitemimage: Create ("Hangzhou", "closeselected.png", this, menu_selector (helloworld: menuclosecallback )); ccmenu * pmenu = ccmenu: Create (pcloseitem, null); this-> addchild (pmenu, 1); this-> m_sprite = ccsprite: Create ("helloworld.png "); cclog ("% d", this-> m_sprite-> retaincount (); Return true;} // RESPONSE event void helloworld: menuclosecallback (ccobject * psender) {cclog ("% d", this-> m_sprite-> retaincount (); this-> m_sprite-> getposition ();}
Okay, run the program and we will find that the program has crashed. Let's analyze it. When we create a ccsprite object, the reference count is 1, and the object is placed in the memory recycle pool. After this frame, the release object is released once, at this time, the object with a reference count of 0 will be released. we press the button to call this object. The memory has been released. Can the program not crash? Next we will change the code to the following to see the effect.
this->m_sprite = CCSprite::create("HelloWorld.png"); CCLog("%d",this->m_sprite->retainCount()); this->m_sprite->retain(); CCLog("%d",this->m_sprite->retainCount());
At this time, the program runs. When you call the function of the button, you will see that the output reference count is 1, because we have manually retaken this object, although the automatic recycle pool has release it, its reference count is still 1. Now that we have retain, we need to remember to release it during the chromatographic structure. In this way, the memory will not be leaked! Another example is ccarray. Let's take a look.
Bool helloworld: Init () {bool Bret = false; do {////////////////////////////////////// /// // parent class initialization /////////////////////////////////////// /// // cc_break_if (! Cclayer: Init (); ccsprite * bomb1 = ccsprite: Create ("closenormal.png"); ccsprite * bomb2 = ccsprite: Create ("closenormal.png "); ccsprite * bomb3 = ccsprite: Create ("closenormal.png"); ccsprite * bomb4 = ccsprite: Create ("closenormal.png"); ccsprite * bomb5 = ccsprite :: create ("closenormal.png"); ccsprite * bomb6 = ccsprite: Create ("closenormal.png"); addchild (bomb1, 1); addchild (bomb2, 1); addchild (bomb3, 1); addchild (bomb4, 1); addchild (bomb5, 1); addchild (bomb6, 1); m_pbombsdisplayed = ccarray: Create (bomb1, bomb2, bomb3, bomb4, bomb5, bomb6, null); this-> scheduleupdate (); Bret = true;} while (0); Return Bret;} void helloworld: Update (cctime DT) {refreshdata ();} void helloworld: refreshdata () {m_pbombsdisplayed-> objectatindex (0)-> setposition (CPP (100,100 ));}
In fact, this principle is similar to the above example. We have created a ccarray object which is not added to other layers at this time, so at the end of this frame, the reference count will be reduced by 1 to 0. Therefore, when you use this frame again, an error will occur! When using cocos2dx memory management, if we create it through the factory method and add it to other layers, we don't have to worry about it, however, if you create a ccobject subclass object through the new method, remember to release this object during structure analysis. If you rehold the object during use, remember to release. In my summary, when we call a function to pass the ccobject subclass object, we should retain it when accepting it, which means that I want to reference this memory space, when you no longer reference this memory space, just release it. When you encounter other problems, you will understand the principles of these problems. Finally, I would like to welcome a large number of users to leave a message. We will discuss cocos2dx together!
Cocos2dx Memory Management Mechanism