cocos-js,内存管理方式

cocos-js,内存管理方式,第1张

概述一.开篇引题 在理解cocos2dx的内存管理机制之前,我们可以先了解下c++中变量的内存空间的分配问题. 我们在c++中写一个类,可以在栈上分配内存空间也可以使用new在堆上分配内存空间,如果类对象是在栈上分配的内存空间,这个内存空间的管理就不是我们的事了,但如果是在堆上分配的内存空间,当然需要我们来手动的delete了! 问题来了,cocos2dx如何管理内存: cocos2dx采用的是在堆上 一.开篇引题

在理解cocos2dx的内存管理机制之前,我们可以先了解下c++中变量的内存空间的分配问题.

我们在c++中写一个类,可以在栈上分配内存空间也可以使用new在堆上分配内存空间,如果类对象是在栈上分配的内存空间,这个内存空间的管理就不是我们的事了,但如果是在堆上分配的内存空间,当然需要我们来手动的delete了!

问题来了,cocos2dx如何管理内存:

cocos2dx采用的是在堆上分配内存空间,既然在堆上分配内存空间,那么如何管理这个内存空间,什么时候应该释放就是个问题了!在程序中,当我们创建了一个对象的时候,这块内存空间经常是被不同的对象引用,如果删除的早了,有对象还在引用这块内存空间那么程序必然要崩溃!所以cocos2dx引入了引用计数的内存管理机制。

二.示例讲解 1.c++代码示例
//对象创建的时候引用计数被设置为1,这个是在它的构造函数中完成的,它会先调用父类Ref的构造函数//Ref::Ref()//: _referenceCount(1) Node * node = new Node();("retain count:%d",node->getReferenceCount());//调用retain方法的时候引用计数增加1node->retain();log("retain count:%d",node->getReferenceCount());//调用release方法的时候引用计数减1,当这个引用计数减为0的时候,在release方法中会delete掉这个对象node->release();log("retain count:%d",node->getReferenceCount());//当我们调用autorelease方法的时候会调用这段代码//PoolManager::getInstance()->getCurrentPool()->addobject(this);//调用autorelease方法的时候对象会被放到自动回收池中,这个自动回收池在每帧结束的时候会调用一次对象的release方法node->autorelease();log("retain count:%d",node->getReferenceCount());

大家经常说的自动回收机制,也就是上边的autorelease方法,当我们调用了autorelease方法以后,我们的对象就会放到这个内存回收池中,当一帧结束的时候这个内存回收池就会释放掉,这个时候在内存回收池中的对象就会被release一下,也就是说引用计数就会减1,如果这个时候引用计数为0,就会删除对象了。如果引用计数不为0的话对象是不会被删除的.

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();    }}voID autoreleasePool::clear(){#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)    _isClearing = true;#endif    std::vector<Ref*> releasings;    releasings.swap(_managedobjectArray);    for (const auto &obj : releasings)    {        obj->release();    }#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)    _isClearing = false;#endif}

下面我们来看一下,通常我们的代码都是怎么写的,来看看这个自动回收机制怎么就做到自动回收了!

//在create的时候调用了sprite的autorelease方法CCSprite * sprite = CCSprite::create("HelloWorld.png");cclog("retain count:%d",sprite->getReferenceCount()); //retain 1this->addChild(sprite);cclog("retain count:%d",sprite->getReferenceCount()); //retain 2

首先我们需要分析一下上边的代码,调用了create工厂方法以后,内部的实现是先new一个CCSprite的对象,这个时候引用计数加1,然后调用autorelease方法,将这个对象放到了自动回收池中,因为这一帧还没有结束,当然引用计数就还是1,所以打印的结果就是1,当我们调用addChild的时候,传入这个CCSprite对象,这个时候在当前层接受了这个对象以后会把它的引用计数加1,表明当前层正在使用这块内存空间,所以现在的retain就是2了。当这一帧结束的时候自动回收池会将对象的引用计数-1,所以现在就只有cclayer在引用这个对象了,当cclayer析构的时候,它会调用这个对象的release方法,这个时候当然就会删除了这个CCSprite对象了。所以什么是自动回收机制呢,自动就是在这一帧结束的时候将对象开始new的时候加的那个引用计数减掉,而让引擎中持有对象引用的其他类去管理这个对象,当持有者析构的时候就删除引用,引擎中的类负责retain和release,这个也算是自动吧!下面就是create方法的实现:

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

有可能有的人又会问,在new 一个node后可不可以就让它的引用计数为0,而不需要调用autorelease方法呢?
如果这样做的话就可能有这种现象发生,当你无意中 new 了一个node后,却忘记使用它,这样它就不会自动回收,而一直占用着内存,造成内存泄漏.

我们再来看下addChild时引用计数+1,removeChild时引用计数-1相关的代码:

在addChild方法里有一句this->insertChild(child,localZOrder);在insertChild方法里有一句_children.pushBack(child);最后在pushBack方法里:voID pushBack(T object){    CCASSERT(object != nullptr,"The object should not be nullptr");    _data.push_back( object );    object->retain();}
2.Js代码示例

我们先来看Js的模板工程代码:

var HelloWorldLayer = cc.Layer.extend({    sprite:null,ctor:function () {        //////////////////////////////        // 1. super init first        this._super();        /////////////////////////////        // 2. add a menu item with "X" image,which is clicked to quit the program        //    you may modify it.        // ask the window size        var size = cc.winSize;        // add a "close" icon to exit the progress. it's an autorelease object        var closeItem = new cc.MenuItemImage(            res.Closenormal_png,res.CloseSelected_png,function () {                cc.log("wade getReferenceCount1:"+hellolabel.getReferenceCount())                cc.log("wade getReferenceCount2:"+this.sprite.getReferenceCount())            },this);        closeItem.attr({            x: size.wIDth - 20,y: 20,anchorX: 0.5,anchorY: 0.5        });        var menu = new cc.Menu(closeItem);        menu.x = 0;        menu.y = 0;        this.addChild(menu,1);        /////////////////////////////        // 3. add your codes below...        // add a label shows "Hello World"        // create and initialize a label        // var hellolabel = new cc.LabelTTF("Hello World","Arial",38);        var hellolabel = cc.LabelTTF.create("Hello World",38);        // position the label on the center of the screen        hellolabel.x = size.wIDth / 2;        hellolabel.y = size.height / 2 + 200;        // add the label as a child to this layer        this.addChild(hellolabel,5);        cc.log("wade getReferenceCount1:"+hellolabel.getReferenceCount())        // add "HelloWorld" splash screen"        this.sprite = new cc.Sprite(res.HelloWorld_png);        this.sprite.attr({            x: size.wIDth / 2,y: size.height / 2        });        this.addChild(this.sprite,0);        cc.log("wade getReferenceCount2:"+this.sprite.getReferenceCount())        return true;    }});

getReferenceCount这个方法就是获取引用计数的,在Ref类中,对于上面的例子,当我们输出计数时,会发现此时都是2. 但是当我们点击关闭按钮的时候,引用计数都是1了,说明在创建的时候就调用了autorelease方法,Js的底层对cocos引擎已经为我们封装了一层.

总结

以上是内存溢出为你收集整理的cocos-js,内存管理方式全部内容,希望文章能够帮你解决cocos-js,内存管理方式所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1080532.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-27
下一篇 2022-05-27

发表评论

登录后才能评论

评论列表(0条)

保存