The use of Cocos2d-x know, which has a set of self-implemented memory management mechanism, different from the general C ++ writing, and before use, understand its principle is necessary, there are already many articles on internal implementation in detail on the Internet. For users, they do not need to have a deep understanding of their internal systems, and pay attention to their "mechanisms" rather than internal implementations, here is just a simple chat about its management methods and usage.
Useless objects and management objects
The Cocos2d-x will automatically clean up useless objects in the next frame, what is useless objects, what is created through the create () method is useless objects.
To briefly describe the code organization design, we have created two helper classes and a container class BaseLayer, managed internal objects on top of BaseLayer, and observed how it automatically managed objects. The constructor method and destructor are implemented, and some logs are printed to facilitate our observation:
1. class LSLayer: public CCNode {2. public: 3. virtual bool init () {4. CCLog ("LSLayer (). init () "); 5. return true; 6 .}; 7. 8. CREATE_FUNC (LSLayer); 9. 10. LSLayer () {11. CCLog ("LSLayer (). () "); 12 .}; 13. ~ LSLayer () {14. CCLog ("LSLayer ().~ () "); 15 .}; 16 .}; 17. 18. class LSSprite: public CCNode {19. public: 20. virtual bool init () {21. CCLog ("LSSprite (). init () "); 22. return true; 23 .}; 24. 25. CREATE_FUNC (LSSprite); 26. 27. LSSprite () {28. CCLog ("LSSprite (). () "); 29 .}; 30. ~ LSSprite () {31. CCLog ("LSSprite ().~ () "); 32 .}; 33 .}; 34. 35. class BaseLayer: public CCLayer {36. public: 37. virtual bool init () {38. CCLog ("BaseLayer (). init () "); 39. // We have created two "useless" objects. 40. LSLayer * layer = LSLayer: create (); 41. LSSprite * sprite = LSSprite: create (); 42. // The layer is used to change to an object under "management" 43. this-> addChild (layer); 44. 45. return true; 46 .}; 47. 48. CREATE_FUNC (BaseLayer); 49. 50. baseLayer () {51. CCLog ("BaseLayer (). () "); 52 .}; 53 .~ BaseLayer () {54. CCLog ("BaseLayer ().~ () "); 55 .}; 56 .}; as shown above, we have created two objects in BaseLayer, layer and sprite, but only layer. To run the BaseLayer code above, we need to create a BaseLayer layer object, add it to the running scenario or layer: addChild (BaseLayer: create (); to ensure BaseLayer starts running. Now let's analyze the running results:
1. // started with addChild (BaseLayer: create (); method, BaseLayer Layer 2 is created and initialized. cocos2d-x debug info [BaseLayer (). ()] 3. cocos2d-x debug info [BaseLayer (). init ()] 4. // We have created two objects in the BaseLayer init method. cocos2d-x debug info [LSLayer (). ()] 6. cocos2d-x debug info [LSLayer (). init ()] 7. cocos2d-x debug info [LSSprite (). ()] 8. cocos2d-x debug info [LSSprite (). init ()] 9. // After the object is created, the "useless" object is released, and the other used object is not released. 10. cocos2d-x de Bug info [LSSprite ().~ ()] Through the comparison of the above two examples, a preliminary understanding of the Object Management of The cocos2d-x, it will automatically clear the "useless object ". To differentiate concepts, we call another object "management object", which is managed and useful. For example, the layer above.
This is a preliminary understanding. Of course, this solves at least one of our questions: we created a member variable through create () During scenario initialization for use as needed, however, it is found that this object does not exist during use, resulting in program crash.
Reclaim objects immediately when they are not used
We continue to evolve the implementation of BaseLayer so that we can observe the situation of each frame object and add the timer function:
1. class BaseLayer2: public CCLayer {2. public: 3. virtual bool init () {4. CCLog ("BaseLayer2 (). init () "); 5. // enable the timer to automatically call update Method 6 at each frame. this-> scheduleUpdate (); 7. return true; 8 .}; 9. 10. // define update statistics 11. int updateCount; 12. LSLayer * layer; 13. LSSprite * sprite; 14. 15. virtual void update (float fDelta) {16. // For the convenience of observation, do not allow the update to print continuously. 17. if (updateCount <3) {18. updateCount ++; 19. CCL Og ("update index: % d", updateCount); 20. 21. // perform operations on different frames for observation. if (updateCount = 1) {23. layer = LSLayer: create (); 24. this-> addChild (layer); 25. sprite = LSSprite: create (); 26. 27 .} else if (updateCount = 2) {28. this-> removeChild (layer, true); 29. 30 .} else if (updateCount = 3) {31. 32 .} 33. 34. CCLog ("update index: % d end", updateCount); 35 .} 36 .}; 37. 38. CREATE_FUNC (BaseLayer2); 39. 40. baseLayer2 (): 41. updateCount (0), 42. layer (NULL), 43. sprite (NULL) 44. {45. CCLog ("BaseLayer2 (). () "); 46 .}; 47. ~ BaseLayer2 () {48. CCLog ("BaseLayer2 ().~ () "); 49 .}; 50 .}; 51. 52. // print the following 53. cocos2d-x debug info [BaseLayer2 (). ()] 54. cocos2d-x debug info [BaseLayer2 (). init ()] 55. // create two objects in the first frame 56. cocos2d-x debug info [update index: 1] 57. cocos2d-x debug info [LSLayer (). ()] 58. cocos2d-x debug info [LSLayer (). init ()] 59. cocos2d-x debug info [LSSprite (). ()] 60. cocos2d-x debug info [LSSprite (). init ()] 61. cocos2d-x debug info [update index: 1 end] 62. // Let's see To sprite useless objects are released between the first and second frames 63. cocos2d-x debug info [LSSprite ().~ ()] 64. cocos2d-x debug info [update index: 2] 65. // remove the management object from the second frame and you can see that it is released immediately, 66 Before index: 2 end. cocos2d-x debug info [LSLayer (). ~ ()] 67. cocos2d-x debug info [update index: 2 end] 68. cocos2d-x debug info [update index: 3] 69. cocos2d-x debug info [update index: 3 end] Unlike useless objects, the management object is immediately released when it is not used, which determines if you want to use this object elsewhere, make a difference before "completely. The update rewrite method is as follows:
1. virtual void update (float fDelta) {2. // For the convenience of observation, do not allow the update to be permanently printed. 3. if (updateCount <3) {4. updateCount ++; 5. CCLog ("update index: % d", updateCount); 6. 7. // perform operations on different frames for observation. if (updateCount = 1) {9. layer = LSLayer: create (); 10. this-> addChild (layer); 11. sprite = LSSprite: create (); 12. CCLog ("% d", layer); 13 .} else if (updateCount = 2) {14. layer-> retain (); 15. this-> removeChild (l Ayer, true); 16. CCLog ("% d", layer); 17 .} else if (updateCount = 3) {18. layer-> release (); 19. if (layer) {20. CCLog ("% d", layer); 21 .} 22 .} 23. 24. CCLog ("update index: % d end", updateCount); 25 .} 26 .}; 27. 28. /// print the following 29. cocos2d-x debug info [update index: 1] 30. cocos2d-x debug info [LSLayer (). ()] 31. cocos2d-x debug info [LSLayer (). init ()] 32. cocos2d-x debug info [LSSprite (). ()] 33. cocos2d- X debug info [LSSprite (). init ()] 34. cocos2d-x debug info [147867424] 35. cocos2d-x debug info [update index: 1 end] 36. cocos2d-x debug info [LSSprite (). ~ ()] 37. cocos2d-x debug info [update index: 2] 38. // The second frame does not release the layer, because it is still useful for managing object 39. cocos2d-x debug info [147867424] 40. cocos2d-x debug info [update index: 2 end] 41. cocos2d-x debug info [update index: 3] 42. // completely deprecated. release immediately. 43. cocos2d-x debug info [LSLayer (). ~ ()] 44. // but the address of the layer object is still available 45. cocos2d-x debug info [147867424] 46. cocos2d-x debug info [update index: 3 end] makes a difference before it is completely unnecessary. If we place layer-> retain (); in the second frame in this-> removeChild (layer, true); then, we know that it is released immediately after removeChild, at this time, the layer object does not exist, and the memory address pointed to by the layer is invalid. If your program continues to run, a memory error will occur.
If the program exits unexpectedly due to a direct error, the program may continue to run. Although the layer is invalid, it is not NULL and may point to an available address, it is possible to continue the execution, and more likely to continue the layer-> retain (); operation. This will affect our judgment. Is there a problem with the program. If this hidden danger is left behind, the difficulty of troubleshooting the error will be greatly increased. For example, the program unexpectedly exits, and the time is good or bad! (This situation may occur after one leaf test, and the frequency is quite high. The test platform: Linux and Android platforms are slightly less likely)
In the third frame, if (layer) is used to determine whether an object is available. if the object is available, we can continue to operate the layer. This method also leaves memory risks, because such a judgment can pass, however, they are not necessarily correct.
In general, we do not need such judgments as if (layer), which is not recommended. Management object, who uses it, then who is controllable! If the retain () is used before the object is destroyed, it can be used before release. If addXXX is used, it can be obtained through getXXX.
In short, whoever uses (references) is the only option you can find, whether it's getting or removing.
As we mentioned earlier, when the management object is not used, it is immediately recycled. So we use the same frame and then remove it? We will continue to rewrite the update method to verify the idea:
1. virtual void update (float fDelta) {2. // For the convenience of observation, do not allow the update to be permanently printed. 3. if (updateCount <3) {4. updateCount ++; 5. CCLog ("update index: % d", updateCount); 6. 7. // perform operations on different frames for observation. if (updateCount = 1) {9. layer = LSLayer: create (); 10. this-> addChild (layer); 11. this-> removeChild (layer, true); 12 .} else if (updateCount = 2) {13. 14 .} else if (updateCount = 3) {15. 16 .} 17. 18. CCLog ("up Date index: % d end ", updateCount); 19 .} 20 .}; 21. 22. /// print the following 23. cocos2d-x debug info [update index: 1] 24. cocos2d-x debug info [LSLayer (). ()] 25. cocos2d-x debug info [LSLayer (). init ()] 26. cocos2d-x debug info [update index: 1 end] 27. // The layer is released between two frames. It is automatically cleared at the first frame. cocos2d-x debug info [LSLayer (). ~ ()] 29. cocos2d-x debug info [update index: 2] 30. cocos2d-x debug info [update index: 2 end] Here we are at the same frame addChild and then removeChild, then what is the nature of the layer, we know that the management object will be released immediately when not used, but it is not immediately released here. What does it mean that the layer is not a management object, but a useless object, and when the frame ends, or when the frame is too large, it is not used. As you can imagine, when frames are too large, some processing is done internally. First, useless objects are automatically cleared or useless objects are converted into management objects, in the future frame, if the management object is not used, it will be released immediately.
Now let's take a look at the structure of a slightly complex point.
1. // perform operations on different frames to observe 2.if (updateCount = 1) {3. layer = LSLayer: create (); 4. sprite = LSSprite: create (); 5. layer-> addChild (sprite); 6. addChild (layer); 7 .} else if (updateCount = 2) {8. 9. this-> removeChild (layer, true); 10 .} else if (updateCount = 3) {11. 12 .} 13. 14. /// print as follows 15. cocos2d-x debug info [update index: 2] 16. cocos2d-x debug info [LSLayer (). ~ 17. cocos2d-x debug info [LSSprite ().~ ()] 18. cocos2d-x debug info [update index: 2 end] We have created two objects: layer and sprite, add sprite to layer, and use layer through addChild (layer, when a layer is removed from the second frame, the layer and sprite objects are released immediately. This is also the function of cocos2d-x automatic management, when the user does not need it, it will also remove the use of other objects.
Perform some Deformation Based on the above conditions:
1. // perform operations on different frames to observe 2.if (updateCount = 1) {3. layer = LSLayer: create (); 4. sprite = LSSprite: create (); 5. layer-> addChild (sprite); 6 .} else if (updateCount = 2) {7. this-> removeChild (layer, true); 8 .} else if (updateCount = 3) {9. 10 .} 11. 12. /// print the following 13. cocos2d-x debug info [update index: 1 end] 14. cocos2d-x debug info [LSLayer (). ~ ()] 15. cocos2d-x debug info [LSSprite ().~ ()] 16. cocos2d-x debug info [update index: 2] 17. cocos2d-x debug info [update index: 2 end] creates two objects: layer and sprite, adds sprite to the layer, and does not process the layer. We know that after the first frame ends, will be released automatically, so it will release the sprite it references, and the nature of the sprite is a bit subtle at this time. How does it process excessive frames? Is it a useless object we call it? Ha! If a layer is automatically managed first, it recycles it and removes the reference to sprite. sprite is useless and automatically recycles it. If the sprite is automatically managed first, it will first become a management object, and then be released immediately when the layer is automatically released and the sprite reference is canceled. In terms of effect, it is completed within one frame. But what is the specific situation? I don't know: p doesn't know either ~ The so-called unknown is unknown, it is also ~
Post
Automatic Management: the so-called automatic management is the object created through the create () method (of course, it is identified by the autorelease () method internally, and create only provides a unified object creation method ), what is useful and useless? We can see retain () and release () in this article. This is a useful and useless implementation principle. If you use retain, you can use release to remove and use it, after further research, we can see that a reference count is maintained in it to determine whether it is used. In the previous article, we know that layer-> addChild (obj), obj is used by layer, the essence of this article is that it internally calls its retain and other methods. You can read the relevant official documents and provide detailed instructions. This article mostly uses abstract concepts to describe its design philosophy, analyze problems that may occur during use from the user's perspective, because there are many implementation methods to achieve the same automatic management effect. Don't pay too much attention to details. If you have any questions, you can use a few small routines like this to verify our ideas. For this article, I only understand the automatic management of cocos2d-x, if there is something wrong with the implementation and concept, please also point out, after all is a simple ~
Cocos2d-x is mainly based on CCNode tree structure management, so the routines created in this paper, written based on CCNode, of course, the automatic management of memory there is a lot of content, such as the implementation of cache, the lifecycle of the message mechanism object. However, based on the principle of who uses it and who handles it, the idea is also clear ~