AutoreleasePoolPoolManager

这里PoolManager是运用了单例模式,cocos2dx中用到了很多单例,例如DirectorSimpleAudioEngine等等。
除此之外,PoolManager实际是对AutoreleasePool的一次封装。

路径

1
base/CCAutoreleasePool.h
base/CCAutoreleasePool.cpp

源码分析

PoolManager

这里先贴上PoolManager的类声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class CC_DLL PoolManager
{
public:
/* 兼容 2.x 版本 */
CC_DEPRECATED_ATTRIBUTE static PoolManager* sharedPoolManager() { return getInstance(); }
static PoolManager* getInstance();

/* 兼容 2.x 版本 */
CC_DEPRECATED_ATTRIBUTE static void purgePoolManager() { destroyInstance(); }
static void destroyInstance();

AutoreleasePool *getCurrentPool() const;

bool isObjectInPools(Ref* obj) const;

friend class AutoreleasePool;

private:
PoolManager();
~PoolManager();

void push(AutoreleasePool *pool);
void pop();

static PoolManager* s_singleInstance;

/* PoolManager 维护一个双端队列,来对
std::deque<AutoreleasePool*> _releasePoolStack;

/* 当前的内存回收池 */
AutoreleasePool *_curReleasePool;
};

PoolManager的实现相对比较简单,所以这里代码就不贴出来了。
PoolManager实际是在维护一个双端队列,貌似就直接把这个双端队列当做栈来用了。
如果我们在cocos2dx中没有调用PoolManagerpushpop的操作的话,那么整个流程就变得更加简单。

整个游戏对内存的操作大致有如下情况:

  • 创建对象

这些对象刚刚开始的时候都会被放入AutoreleasePool中,然后马上进行一次clear
这里主要是对那些创建了,但是没有使用的对象进行清除。

  • 对象和渲染树

渲染树节点都是Node的子类
然后加到渲染树中的时候,会调用Ref::retain,具体见Node
若是从渲染树种删除,可以选择是否清除,这里的清除就是调用Ref::release,具体见Node

AutoreleasePool

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class CC_DLL AutoreleasePool
{
public:
AutoreleasePool();
AutoreleasePool(const std::string &name);

~AutoreleasePool();

/* 添加一个对象到内存回收池中 */
/* 这里不会检查重复元素 */
/* 所以Ref::autorealse不要调用多次的原因 */
void addObject(Ref *object);

/* 调用内存回收池中所有对象的Ref::release方法 */
/* 然后情况当前的内存回收池的所有对象 */
/* 这个方法主要是清理哪些创建出来,但是没有使用的对象 */
void clear();

/* 调试模式下的方法 */
/* 可能是由于cocos2dx不是线程安全的吧 */
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
bool isClearing() const { return _isClearing; };
#endif

bool contains(Ref* object) const;

void dump();

private:
/* 内存回收池,使用std::vector管理 */
std::vector<Ref*> _managedObjectArray;
/* 这个回收池的名字,主要用于调试 */
std::string _name;

#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
bool _isClearing;
#endif
};

上面我们也提到了clear方法,让我们来看看具体是什么个鸟东西=。=

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void AutoreleasePool::clear()
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = true;
#endif
for (const auto &obj : _managedObjectArray)
{
obj->release();
}
_managedObjectArray.clear();
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = false;
#endif
}

噢~~原来只是遍历下数组,然后直接调用每个对象的Ref::release方法,最后直接清空这个数组。
这个clear没帧都会被调用,为了清除那些创建出来,但是没有使用的对象。

至于这个每帧的调用在Director中实现,这几天我开篇文章来分析分析=。=

总结

对于这几天写的文章,应该做一个总结,即RefNodeAutoreleasePoolPoolManager等类的结合分析。