Cocos2d-x 3.x: How to make a reasonable memory allocation (use Autoreleasepool to manage memory reasonably)
This article is reproduced in-depth understanding of Cocos2d-x 3.x: How to make reasonable memory allocation
Imagine a scenario in which a typical memory is allocated reasonably: within a frame, there are several functions, each of which creates a series of sprites, each of which will occupy a certain amount of memory, the total number of sprites may be 1000, and a function will create only 10 sprites. The created sprite is only used in this function, and the approximate code is as follows:
12345 |
for ( int i = 0; i < 10; i++) { Sprite* s = Sprite::create(); //-- doSomething -- } |
Does this cause a memory leak?
The answer is of course not, but this causes the memory spikes in the frame to be too high, because in the automatic memory management of the engine, all the free memory operations are done at the end of each frame, so even if the requested memory is not used elsewhere in this frame, its memory will not be released with the end of the scope.
So how do we optimize this code? As follows
123456 |
AutoreleasePool pool; for ( int i = 0; i < 10; i++) { Sprite* s = Sprite::create(); //-- doSomething -- } |
Just add the first sentence to the function
It is possible to automatically release the Create pointer at the end of the function, so why does it have such a magical effect? Let's analyze the constructor and destructor of this function, and first analyze the constructor:
123456 |
AutoreleasePool::AutoreleasePool() : _name( "" ) { _managedObjectArray.reserve(150); PoolManager::getInstance()->push( this ); } |
He push himself into Poolmanager's Singleton, and we go into push to see how it's implemented.
1234 |
void PoolManager::push(AutoreleasePool *pool) { _releasePoolStack.push_back(pool); } |
Press this directly into the _releasepoolstack stack, what effect will this have? This will have to say the implementation of autorelease, it is well known that the automatic memory management mechanism of the CREATE function depends on the Autorelease function, then the Autorelease function is what to use it:
12345 |
Ref* Ref::autorelease() { PoolManager::getInstance()->getCurrentPool()->addObject( this ); return this ; } |
Add an object to a pool, so what does Getcurrentpool get for that memory management pool?
1234 |
AutoreleasePool* PoolManager::getCurrentPool() const { return _releasePoolStack.back(); } |
That's the last pool we've added through push, so every Autoreleasepool object that you create will be pressed into the poolmanager. Then the subsequent Autorelease action is to add the object to the newly created Autoreleasepool object.
So what is the final way to let the function automatically free up memory at the end of the function? We know that when the scope ends, the destructor of the normal object is called, so let's see what the Autoreleasepool destructor does.
12345 |
AutoreleasePool::~AutoreleasePool() { clear(); PoolManager::getInstance()->pop(); } |
The first one is the clear function, which is a very critical function that we trace in
12345678 |
void autoreleasepool:: Clear () {&NBSP;&NBSP; for ( const auto &obj : _managedobjectarray) &NBSP;&NBSP;&NBSP;&NBSP; { &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; obj->release (); &NBSP;&NBSP;&NBSP;&NBSP; }&NBSP;&NBSP; &NBSP;&NBSP;&NBSP;&NBSP; _managedobjectarray.clear (); } |
It will perform all of the AddObject objects once the release operation. This will allow the memory to be freed automatically at the end of the function.
1 |
PoolManager::getInstance()->pop(); |
This line of code mainly pops the current Autoreleasepool object from Poolmanager (because the current object is already refactored)
The above is a reasonable management of memory by using Autoreleasepool.
Cocos2d-x 3.x: How to make a reasonable memory allocation (use Autoreleasepool to manage memory reasonably)