Cocos2dx引擎7-内存管理机制

在C++中,可以再栈上分配内存也可以在堆上分配内存;如果对象在栈上分配内存,那么内存释放就不管我们的事了;如果在堆上分配内存,那么我们还需要负责将分配的内存在不需要的时候释放;

C++的动态内存管理建议遵守谁申请谁释放的原则,即谁使用new,那么谁就需要使用delete释放内存。在同一个生命周期内,这是很容易实现的;如果对象的生命周期超出了创建对象的函数,我们就很难再遵循谁申请谁释放的原则了,我们必须在函数外的某个合适的地方释放对象,如果这个对象同时被多个对象引用,问题就很复杂了,必须保证所有该对象的引用者都不再需要它了才可以释放,在实际使用中这点是很难保证的。

于是就出现了各种各样的内存管理机制,如:垃圾回收器,智能指针,引用计数......Cocos最早的版本是使用Object-C实现,后来为了实现跨平台就使用C++重新实现,也就有了今天的Cocos2dx;故Cocos2dx使用内存管理机制为Object-C最原始的内存管理机制-引用计数。没做过IOS开发的同学可能不太熟悉这种内存管理机制…

 

Cocos2dx内部所有的类都是继承了Ref类:

class CC_DLL Ref
{
public:
    void retain();       //引用计数加1
    void release();      //引用计数减1,若引用计数为0,则delete对象
    Ref* autorelease();  //将对象添加到内存统一管理机制中
    unsigned int getReferenceCount()const; //获取引用计数
 
protected:
    unsigned int _referenceCount;  //引用计数
};

auto sprite = Sprite::create("1.png");
log("sprite, getReferenceCount1 = %d",sprite->getReferenceCount);
sprite->retain();
log("sprite, getReferenceCount2 = %d", sprite->getReferenceCount);
sprite->release();
log("sprite, getReferenceCount3 = %d",sprite->getReferenceCount);
this->addChild(sprite);
log("sprite, getReferenceCount4 = %d",sprite->getReferenceCount);

输出结果为

sprite, getReferenceCount1 = 1

sprite, getReferenceCount2 = 2

sprite, getReferenceCount3 = 1

sprite, getReferenceCount4 = 2

由输出结果可以发现,在sprite刚创建时引用计数为1;使用retain()后,引用计数加1;使用release()后,引用计数减1;调用addChild(sprite)后,引用计数加1,因为在addChild实现中会调用sprite的retain();


下面看一下Cocos2dx中自动内存管理

Sprite* Sprite::create(const std::string& filename)
{
    Sprite *sprite = new(std::nothrow) Sprite();
    if (sprite &&sprite->initWithFile(filename))
    {
        sprite->autorelease();
        return sprite;
    }
    CC_SAFE_DELETE(sprite);
    return nullptr;
}

在Sprite::create中首先会使用C++动态内存管理方式(new)创建Sprite对象,然后会调用sprite->autorelease()方法,autorelease()方法的作用是将sprite对象添加到自动内存管理池中;

Ref* Ref::autorelease()
{
   PoolManager::getInstance()->getCurrentPool()->addObject(this);
    return this;
}
PoolManager* PoolManager::getInstance()
{
    if (s_singleInstance == nullptr)//第一次被调用时成立
    {
        s_singleInstance = newPoolManager();//创建内存管理池
        newAutoreleasePool("cocos2d autorelease pool");//创建内存自动释放池
    }
    return s_singleInstance;
}

PoolManager::getInstance()方法在第一次被调用时会创建一个内存管理池和内存自动释放池,然后将内存自动释放池放入到内存管理池中;PoolManager中存储AutoreleasePool的成员变量为

std::vector<AutoreleasePool*>_releasePoolStack;

在AutoreleasePool中存储需要自动内存管理的成员变量为

std::vector<Ref*>_managedObjectArray;

poolManager->getCurrentPool()会反回_releasePoolStack最顶端的

AutoreleasePool变量作为当前自动释放池;

autoreleasePool->addObject(this)会将当前对象放入_managedObjectArray中;

int Application::run()
{
   while(!glview->windowShouldClose())
    {
            director->mainLoop();
    }
}
 
void DisplayLinkDirector::mainLoop()
{
    drawScene();
    PoolManager::getInstance()->getCurrentPool()->clear();
}

AutoreleasePool::clear()中会将加入到自动释放池中的对象release,即引用计数减1,若引用计数为0,将会将该对象delete。

 

通过上述自动释放池的释放流程可以看到,添加到自动释放池中的对象在第一帧绘制完成后将会全部release。再一次调用autorelase前,自动释放池为空,这样做法是为了使每一个对象在第一帧会之前保持内存空间。

 

本人确实不太明白设计cocos2dx这个模块的人怎么想的…
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值