cocos中所有的对象都是继承自Ref基类,Ref的职责就是对对象进行引用计数管理

内存管理中最重要的是三个方法retain()、release()、autorelease()

在cocos中创建对象的标准流程是:

创建对象->初始化->添加到自动内存管理->返回创建成功的对象

就比如下面这段代码1:创建Node对象

//代码1
Node * Node::create()
{
Node * ret = new (std::nothrow) Node();
if (ret && ret->init())
{
ret->autorelease();
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}

在代码1中,我们只需要调用create方法就可以实现创建对象、初始化和自动管理内存。

在cocos中有的函数中直接使用了create的宏定义,调用对象的create方法就可以执行代码2,实现的功能和代码1是一样的。

//代码2
#define CREATE_FUNC(__TYPE__) \
static __TYPE__* create() \
{ \
__TYPE__ *pRet = new(std::nothrow) __TYPE__(); \
if (pRet && pRet->init()) \
{ \
pRet->autorelease(); \
return pRet; \
} \
else \
{ \
delete pRet; \
pRet = nullptr; \
return nullptr; \
} \
}

代码2中调用autorelease方法,将对象加入自动内存管理池自动管理。

代码3是autorelease方法的实现

//代码3
Ref* Ref::autorelease()
{
PoolManager::getInstance()->getCurrentPool()->addObject(this);
return this;
}

首先看一下代码4,PoolManager的getInstance方法

在代码4中创建了PoolManager对象并调用了this的AutoreleasePool方法(代码5)

"cocos2d autorelease pool"是这个自动管理池的name

//代码4
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;
}

在代码5中可以看到先是对_managedObjectArray预留空间,然后将this加了进去

//代码5
AutoreleasePool::AutoreleasePool(const std::string &name)
: _name(name)
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
, _isClearing(false)
#endif
{
_managedObjectArray.reserve(150);
PoolManager::getInstance()->push(this);
}

在代码3中还调用了getCurrentPool方法用来获取当前的内存管理池

//代码6
AutoreleasePool* PoolManager::getCurrentPool() const
{
return _releasePoolStack.back();
}

然后把this加入到当前的内存管理池中作为一个ref对象进行管理,如代码7

//代码7
void AutoreleasePool::addObject(Ref* object)
{
_managedObjectArray.push_back(object);
}

整个流程如下图所示

自动内存管理的结构如下图,用一个栈来存储多个自动内存管理池,在自动内存管理池中又有若干个ref对象。

在内存管理中主要是靠引用计数来记录对象的使用情况,当一个对象被create时会给它分配内存,并且会调用retain()方法让引用计数+1;当调用release()时会让引用计数-1,release时会检查引用计数是否为0,引用计数为0时会调用delete删除对象并释放内存。

在每一帧结束时会清理当前的内存管理池,将每一个ref对象的引用计数都-1,这帧结束之后,内存管理池中就没有这个ref对象了,引用计数是ref自己的属性,当下一次被release时如果引用计数=0,就会被释放。

void Director::mainLoop()
{
......
PoolManager::getInstance()->getCurrentPool()->clear();
}
}
void AutoreleasePool::clear()
{
std::vector<Ref*> releasings;
releasings.swap(_managedObjectArray);
for (const auto &obj : releasings)
{
obj->release();
}
}

retain()和release()只是帮助我们记录一个对象的引用次数,在程序中几乎不用手动调用。

最新文章

  1. python中的binascii
  2. I.MX6 Linux mipi配置数据合成
  3. 【UVA 11383】 Golden Tiger Claw (KM算法副产物)
  4. (史上最全的ios源码汇总)
  5. iOS8发展~Swift(三)UI详细解释
  6. cocos2dx 制作单机麻将(二)
  7. hdu_1558_Segment set(并查集+计算几何)
  8. SpringMVC简版教程、部分功能
  9. caffe训练模型中断的解决办法(利用solverstate)
  10. Win10系列:JavaScript小球运动示例
  11. 编程实战——电影管理器之XML存储电影信息数据
  12. linux下如何查看多核负载情况【转】
  13. oracle进行字符串拆分并组成数组
  14. python 简单搭建阻塞式单进程,多进程,多线程服务
  15. JVM类加载机制详解(二)类加载器与双亲委派模型
  16. js 正则表达式 exec 和 match的使用
  17. tiny6410的linux操作系统实验开发
  18. angular6开发不完全笔记(一) -- ng-cli
  19. Ubuntu14.04下安装docker 1.9
  20. Java中生成帮助文档

热门文章

  1. PHPExcel 设置表格边框
  2. jsp页面关建字查询出记录后,点下一页关键字会清空,怎么保持关键字不变而进行下一页操作?
  3. 谷歌BERT预训练源码解析(三):训练过程
  4. oracle WHERE子句中的连接顺序
  5. 箭头函数表达式和声名式函数表达式的区别以及 Function.prototype的bind, apply,call方法
  6. GPU版TensorFlow怎么指定让CPU运行
  7. H3C 主要局域网技术
  8. ThinkPHP3.2版本安全更新
  9. 【t085】Sramoc问题
  10. P1104 最大公约数和最小公倍数问题