Analyze the memory management operations of Cocos2d x in iOS development

  • 2020-05-12 06:14:57
  • OfStack

1, IOS and image memory
On IOS, images are automatically scaled to 2 to the N power. For example, a picture of 1024*1025, the memory occupied and a picture of 1024*2048 is 1. The calculation formula of the memory size of the image is; Length * width *4. So the memory footprint of one 512 by 512 is 512 by 512 by 4, which is 1M. Other dimensions and so on. (ps: maximum size supported on IOS is 2048*2048).

2, cocos 2d-x image cache
Cocos2d-x will use spriteWithFile or spriteWithSpriteFrameName when constructing a Sprite. Either way, cocos2d-x will load the image into the cache. If the image is loaded for the first time, the image is loaded into the cache and then read from the cache. If it already exists in the cache, it is extracted directly from the cache, eliminating the loading process.

Image caching is handled by the following two classes: CCSpriteFrameCache and CCTextureCache

CCSpriteFrameCache loads a large spliced image, and each small image is just one region in the large image. The information of these regions is saved in the plist file. To use it, you just need to load it into the area according to the name of the little diagram.

CCTextureCache is a normal image cache where all of our directly loaded images are placed by default to increase the efficiency of the call.

Therefore, each time an image is loaded, or a Mosaic is loaded via plist, the entire image is loaded into memory. If you don't release it, it's going to be 1.

3. Render memory
Don't think that when you're computing memory, you're just computing the memory that's loaded into the cache. Take a picture of 1024*1024 for example.


CCSprite *pSprite = CCSprite::spriteWithFile("a.png");

After calling the above line of code, you can see in the LEAKS tool that it increases memory by approximately 4M. And then call

addChild(pSprite);

At this point, memory is increased by 4M. That is, 1 image, if it needs to be rendered, then the memory it consumes will be X2.

Take a look at the images loaded via plist. For example, this large image is 2048*2048. I want to load a small 32 by 32 image


CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("b.plist");

Now the memory increases by 16M

CCSprite *pSpriteFrame = CCSprite::spriteWithSpriteFrameName("b1.png");

b.png is 32*32, so I thought I would add 1 bit of memory, but I actually added 16M. That is, as long as one part is rendered, the entire image will be loaded.

However, the situation is not so bad. If these already rendered images are reloaded, the memory will not increase any further. For example, another area of 100 b.plist is added, and the image memory will still increase by 16+16 = 32M, but will not continue to rise.

4. Cache release
If there are many scenes in the game, you can free up the memory of the first scene when switching scenes to prevent the total memory from being too high.


CCTextureCache::sharedTextureCache()->removeAllTextures(); Release all images loaded so far CCTextureCache::sharedTextureCache()->removeUnusedTextures(); Count the reference to 1 The picture is released CCTextureCache::sharedTextureCache()->removeTexture(); Release a single image CCSpriteFrameCache with CCTextureCache The method of release is similar.

It is important to note the release timing. 1 generally releases resources when switching scenes. If you switch from A scene to B scene, the sequence of functions called is B::init()-- > A::exit()---- > B::onEnter() but if you use a toggle effect, such as CTransitionJumpZoom::transitionWithDuration, the order in which the function is called changes to B::init()-- > B::onEnter()---- > A::exit() and the second way will have a 1 moment to stack the resources of the two scenes in 1, if you do not take excessive, it is likely to crash due to the memory crunch.

Sometimes, when all resources are forced to be released, an executing animation will lose its reference and an exception will pop up. You can call CCActionManager::sharedManager()- > removeAllActions (); To solve it.

5. Memory management
1. An overview of the
cocos2d-x was originally ported from the objective C version of cocos2d. Therefore, for memory management, a reference counter method similar to NSObject is used, and the associated interface is placed in the CCObject class.

2. Reference counters -- manage memory manually
Objects of CCObject and its subclasses are automatically set to 1 when they are created. Each subsequent call to retain has a reference count of +1. Each time release is called, reference count -1; If the reference count =0, then directly delete this.
The relevant interfaces are as follows:


// citations +1
virtual void CCObject::retain(void);
// citations -1 ; If reference counter =0 , delete this ;
virtual void CCObject::release(void);
//helper Method to quickly determine that the current object is only only 1 reference
bool CCObject::isSingleRefrence(void);
// Number of references returned
unsigned int CCObject::retainCount(void);

Principle 1: whoever generates (new, copy) is responsible for release.
Example:

CCObject *obj=new CCObject;
...
obj->release();

retain is used for pointer passing and assignment. It means to have. This is often used for pointer assignments.
Principle 2: who retain, who is responsible for release.
Example:


obj->retain();
...
obj->release();

Principle 3: when you pass an assignment, you need retain parameters first, release pointer later, and finally the assignment. (note that since self-assignment checks are not used, this sequence cannot be wrong.)
Example:


void CCNode::setGrid(CCGridBase* pGrid)
{
            CC_SAFE_RETAIN(pGrid);
            CC_SAFE_RELEASE(m_pGrid);
            m_pGrid = pGrid;
}


3. Automatic pool release -- automatic memory management

Principle 4: for objects that use autorelease, forget about it and each frame will be automatically released.

Related interfaces:


CCObject* CCObject::autorelease(void);
 

Example:

CCObject *obj=new CCOjbect;
obj->autorelease();
...

Managing memory completely by hand is tedious, and cocos2d-x provides the automatic release pool CCPoolManager. Place the object in the auto-release pool, and at the end of each frame, the object in the release pool is automatically release.


4.CCNode node management

cocos2d-x USES nodes to form a tree, which is traversed during rendering. CCNode is the parent class of all node classes. It internally USES an CCArray object to manage all its child nodes. When an object is added as a child node, it is actually added to the CCArray object, and the retain method of this object is called. Similarly, the release method is called when it is removed from CCArray.

Related interfaces:


virtual void addChild(CCNode * child);
virtual void addChild(CCNode * child, int zOrder);
virtual void addChild(CCNode * child, int zOrder, int tag);
virtual void removeChild(CCNode* child, bool cleanup);
void removeChildByTag(int tag, bool cleanup);
virtual void removeAllChildrenWithCleanup(bool cleanup);

When switching scenes, the system will traverse the nodes of the whole tree to release.

5. Static factory

There are a number of static factory methods in cocos2d-x, all of which call the autorelease function on the this pointer. Such as these methods in CCSprite:


static CCSprite* spriteWithTexture(CCTexture2D *pTexture);
static CCSprite* spriteWithTexture(CCTexture2D *pTexture, const CCRect& rect);
static CCSprite* spriteWithTexture(CCTexture2D *pTexture, const CCRect& rect, const CCPoint& offset);
static CCSprite* spriteWithSpriteFrame(CCSpriteFrame *pSpriteFrame);
static CCSprite* spriteWithSpriteFrameName(const char *pszSpriteFrameName);
static CCSprite* spriteWithFile(const char *pszFileName);
static CCSprite* spriteWithFile(const char *pszFileName, const CCRect& rect);
static CCSprite* spriteWithBatchNode(CCSpriteBatchNode *batchNode, const CCRect& rect);
 

These methods are implemented internally: memory allocation, initialization, setting autorelease. Using a static factory to generate objects simplifies the code and is officially recommended.

6. Class cache mechanism

There are 1 class cache in cocos2d-x, which are singleton class managers.


CCAnimationCache
CCSpriteFrameCache
CCTextureCache

These cache also use the ratain and release methods internally to prevent these resources from being released.
Using these cache, we can save some preloaded resources and call it at a convenient time to bind to some objects. Note that these cache will not be deleted automatically when the scene is switched, so you need to manually call the purgeXXXX method to clean it up.


Related articles: