Coco2d-x 内存管理笔记
来源:互联网 发布:saga淘宝 编辑:程序博客网 时间:2024/06/16 19:31
Coco2d-x内存管理包括3个类,Ref(引用计数类)、AutoreleasePool(自动释放池)、PoolManager(自动释放池管理类)。
- Ref:Ref是所有需要内存管理的类的基类,用于管理对象的引用计数。Ref中包含两种内存管理函数:手动管理函数retain()(引用计数加1)和release()(引用计数减1,当引用计数为0时,deleted this释放自身),自动管理类函数autorelease()(将对象自身交与PoolManager的栈顶AutoreleasePool管理,PoolManager会每帧都会release()一次所有autorelease对象)。
- AutoreleasePool:AutoreleasePool是用于管理autorelease对象的管理类。本身是一个Vector,最少可以装150个对象(初始化reverse()了150个elements)。Ref中autorelease()调用的是PoolManager的栈顶的AutoreleasePool对象中的addObject()函数,将对象自身加入AutoreleasePool。PoolManager中每帧调用的是栈顶的AutoreleasePool对象的clear()函数release()一次全部autorelease对象(只是引用计数减1,不一定会delete)。
- PoolManager:PoolManager是用于管理AutoreleasePool的一个管理类,它是一个单实例类,初始化可以包含10个池,其自身也是一个Vector,当作栈使用,一般来说PoolManager会用到的函数就只有getCurrentPool(),返回的是栈顶即Vector最后一个AutoreleasePool,因为一般来说只用一个AutoreleasePool就可以了,所以push(AutoreleasePool *pool)和pop()基本不会使用。
操作流程(以Scene为例子)
1.假设要新建一个场景:auto scene = Scene::create()
//--------------------------------------------------------------------//// Scene::create()////--------------------------------------------------------------------Scene* Scene::create(){ Scene *ret = new (std::nothrow) Scene(); if (ret && ret->init()) { ret->autorelease(); return ret; } else { CC_SAFE_DELETE(ret); return nullptr; }}
在new一个Scene之后,调用该Scene的autorelease()函数,将该对象加入到自动释放池中
2.ret->autorelease();
//--------------------------------------------------------------------//// Ref:::autorelease()////--------------------------------------------------------------------Ref* Ref::autorelease(){ PoolManager::getInstance()->getCurrentPool()->addObject(this); return this;}
该Scene的autorelease()函数中,第一次调用PoolManager的getInstance(),需要进行PoolManager的初始化
3.PoolManager初始化:PoolManager::getInstance()
//--------------------------------------------------------------------//// PoolManager:::getInstance()////--------------------------------------------------------------------PoolManager* PoolManager::getInstance(){ if (s_singleInstance == nullptr) { s_singleInstance = new (std::nothrow) PoolManager(); // Add the first auto release pool new AutoreleasePool("cocos2d autorelease pool"); } return s_singleInstance;}
初始化包括:new一个PoolManager和new一个名为cocos2d autorelease pool的默认AutoreleasePool。
//--------------------------------------------------------------------//// PoolManager:::PoolManager()////--------------------------------------------------------------------PoolManager::PoolManager(){ _releasePoolStack.reserve(10);}
new一个PoolManager会申请一个至少可以保存10个AutoreleasePool的数组并当作栈来使用,其实一般只需要用到1个AutoreleasePool
//--------------------------------------------------------------------//// AutoreleasePool:::AutoreleasePool()////--------------------------------------------------------------------AutoreleasePool::AutoreleasePool(const std::string &name): _name(name){ _managedObjectArray.reserve(150); PoolManager::getInstance()->push(this);}new一个AutoreleasePool会申请一个至少可以保存150个Ref类对象的数组,并把自身push到PoolManager的自动释放池栈的栈顶
//--------------------------------------------------------------------//// PoolManager:::push()////--------------------------------------------------------------------void PoolManager::push(AutoreleasePool *pool){ _releasePoolStack.push_back(pool);}
一般来说,PoolManager只会push一个默认的AutoreleasePool,不再需要其他的AutoreleasePool,所以PoolManager的自动释放池栈中一般只有一个elements
4.初始化PoolManager之后,获取栈顶的AutoreleasePool:PoolManager::getInstance()->getCurrentPool()
//--------------------------------------------------------------------//// AutoreleasePool:::getCurrentPool()////--------------------------------------------------------------------AutoreleasePool* PoolManager::getCurrentPool() const{ return _releasePoolStack.back();}因为Vector当作栈使用,所以_releasePoolStack的尾部就是栈顶,返回尾部_releasePoolStack.back()
5.获取当前AutoreleasePool后,把该Scene加入AutoreleasePool: PoolManager::getInstance()->getCurrentPool()->addObject(this);
//--------------------------------------------------------------------//// AutoreleasePool:::addObject()////--------------------------------------------------------------------void AutoreleasePool::addObject(Ref* object){ _managedObjectArray.push_back(object);}把该Scene加入_managedObjectArray尾部
6.autorelease对象会在mainLoop()中调用PoolManager::getInstance()->getCurrentPool()->clear()进行内存清理
//--------------------------------------------------------------------//// DisplayLinkDirector:::mainLoop()////--------------------------------------------------------------------void DisplayLinkDirector::mainLoop(){ if (_purgeDirectorInNextLoop) { _purgeDirectorInNextLoop = false; purgeDirector(); } else if (_restartDirectorInNextLoop) { _restartDirectorInNextLoop = false; restartDirector(); } else if (! _invalid) { drawScene(); // release the objects PoolManager::getInstance()->getCurrentPool()->clear(); }}在draw所有的scene之后(一帧所有的rendering后),进行内存清理
//--------------------------------------------------------------------//// AutoreleasePool:::clear()////--------------------------------------------------------------------void AutoreleasePool::clear(){ std::vector<Ref*> releasings; releasings.swap(_managedObjectArray); for (const auto &obj : releasings) { obj->release(); }}
这里用到swap()函数releasings.swap(_managedObjectArray),大概就像交换两个vector的保存数据的内存首地址,然后AutoreleasePool中的_managedObjectArray的保存数据的内存首地址指向releasings的保存数据的内存首地址,两个vector中的内容交换后_managedObjectArray空了,releasings需要手动清空,即遍历releasings调用elements的release()进行内存清理。
7.swap()的使用方法
vector<int> vec(100000, 0);cout << "vec[0] = " <<vec[0] << " ";cout << "vec[100000 - 1] = " << vec[100000 - 1] << endl;for (int i = 0; i < 100000 - 2; ++i) vec.pop_back();cout << "After pop_back() (100000 - 2) times , vec.capacity() = " << vec.capacity() << endl;vector<int>(vec).swap(vec);//vector<int>(vec)是用vec作为形参新建一个vector,此时vec只剩两个elements了,所以新建的vector容量为2cout << "After swap() with vector<int>(vec) (a new vector only have 2 elements), vec.capacity() = " << vec.capacity() << endl;
三个类的所有函数
//--------------------------------------------------------------------//// Ref////--------------------------------------------------------------------Ref::Ref(): _referenceCount(1) // when the Ref is created, the reference count of it is 1}Ref::~Ref(){ }void Ref::retain(){ CCASSERT(_referenceCount > 0, "reference count should be greater than 0"); ++_referenceCount;}void Ref::release(){ CCASSERT(_referenceCount > 0, "reference count should be greater than 0"); --_referenceCount; if (_referenceCount == 0) { delete this; }}Ref* Ref::autorelease(){ PoolManager::getInstance()->getCurrentPool()->addObject(this); return this;}unsigned int Ref::getReferenceCount() const{ return _referenceCount;}//--------------------------------------------------------------------//// AutoreleasePool////--------------------------------------------------------------------AutoreleasePool::AutoreleasePool(): _name(""){ _managedObjectArray.reserve(150); PoolManager::getInstance()->push(this);}AutoreleasePool::AutoreleasePool(const std::string &name): _name(name){ _managedObjectArray.reserve(150); PoolManager::getInstance()->push(this);}AutoreleasePool::~AutoreleasePool(){ CCLOGINFO("deallocing AutoreleasePool: %p", this); clear(); PoolManager::getInstance()->pop();}void AutoreleasePool::addObject(Ref* object){ _managedObjectArray.push_back(object);}void AutoreleasePool::clear(){ std::vector<Ref*> releasings; releasings.swap(_managedObjectArray); for (const auto &obj : releasings) { obj->release(); }}bool AutoreleasePool::contains(Ref* object) const{ for (const auto& obj : _managedObjectArray) { if (obj == object) return true; } return false;}//--------------------------------------------------------------------//// PoolManager////--------------------------------------------------------------------PoolManager* PoolManager::s_singleInstance = nullptr;PoolManager* PoolManager::getInstance(){ if (s_singleInstance == nullptr) { s_singleInstance = new (std::nothrow) PoolManager(); // Add the first auto release pool new AutoreleasePool("cocos2d autorelease pool"); } return s_singleInstance;}void PoolManager::destroyInstance(){ delete s_singleInstance; s_singleInstance = nullptr;}PoolManager::PoolManager(){ _releasePoolStack.reserve(10);}PoolManager::~PoolManager(){ CCLOGINFO("deallocing PoolManager: %p", this); while (!_releasePoolStack.empty()) { AutoreleasePool* pool = _releasePoolStack.back(); delete pool; }}AutoreleasePool* PoolManager::getCurrentPool() const{ return _releasePoolStack.back();}bool PoolManager::isObjectInPools(Ref* obj) const{ for (const auto& pool : _releasePoolStack) { if (pool->contains(obj)) return true; } return false;}void PoolManager::push(AutoreleasePool *pool){ _releasePoolStack.push_back(pool);}void PoolManager::pop(){ CC_ASSERT(!_releasePoolStack.empty()); _releasePoolStack.pop_back();}
- Coco2d-x 内存管理笔记
- COCOS学习笔记--Cocod2dx内存管理(三)-Coco2d-x内存运行原理
- coco2d-x内存优化
- coco2d-x学习笔记
- Coco2d-x Framebuffer笔记
- coco2d-x 学习笔记2
- cocos2d-x-3.1 常用宏 (coco2d-x 学习笔记五)
- cocos2d-x-3.1 NotificationCenter (coco2d-x 学习笔记八)
- coco2d笔记
- coco2d 笔记
- [coco2d-x]pvr与png的内存占用
- cocos2d-x学习笔记:内存管理
- 【cocos2d-x 3.x 学习笔记】对象内存管理
- coco2d-x手记
- coco2d-x使用备忘录
- coco2d-x 动作类
- Coco2d-x linux编译
- coco2d-x xuexi
- phpcms v9调用外部数据库的方法
- Linux下查找搜索文件Find命令使用
- UML类图几种关系的总结
- 解决Android studio开发找不到HttpClient问题
- 几种任务调度的 Java 实现方法与比较
- Coco2d-x 内存管理笔记
- Fragment
- Socket Tcp Java
- git仓库删除所有提交历史记录,成为一个干净的新仓库
- 网盘 线上预览(openoffice)
- spark standalone的安装及使用
- centos 网卡绑定
- 【bzoj1224】彩票 dfs
- Android中的闹钟与通知(附Demo)