使用CSLoader::create建立场景,场景切换时内存会泄漏。
测试平台:Xcode 6.1 + iOS 8.2 + Cocos引擎v1.0 Preview版
笔者照着两个场景中的场景切换按钮一阵狂点,切换N次场景后,Test1和Test2的内存占用都稳定的保持在16.5M,唯独Test3,场景每切换3次左右,内存占用就上升0.1M。
该BUG是在笔者做一个实际项目时发现的,比起Test3,笔者的实际项目中,每切换2、3次场景内存占用就上升2M,笔者一阵狂点,内存占用轻松突破300M,对于内存配备仅1G的iPadMini2来说,这种泄漏是相当危险的。
导致内存占用持续上升的原因是,在CSLoader中对资源进行了retain(),在随后的addChild()里,资源又被retain(),引用计数为2,但是在popScene()中资源只被release()一次,导致资源的引用计数最终变为1而不是0,占用内存自然不能被释放。
据说Cocos2d-x v3.3RC2以后的版本已经解决这个问题,即在CSLoader中不进行任何的retain()动作。
测试平台:Xcode 6.1 + iOS 8.2 + Cocos引擎v1.0 Preview版
新建工程时默认的HelloWorldScene.cpp,将Touch事件改为Clicked事件,在回掉中切换场景。
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
auto rootNode = CSLoader::createNode("MainScene.csb");
addChild(rootNode);
auto closeItem = static_cast<ui::Button*>(rootNode->getChildByName("Button_1"));
closeItem->addClickEventListener(CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
return true;
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
auto newScene = myScene::creatScene();
Director::getInstance()->pushScene(newScene);
}
以下为测试用myScene类
myScene.h
#ifndef __playC2DX__myScene__
#define __playC2DX__myScene__
#include "cocos2d.h"
class myScene : public cocos2d::Layer
{
public:
static cocos2d::Scene *creatScene();
CREATE_FUNC(myScene);
bool init();
void onBnClicked(Ref *pSender);
};
myScene.cpp
#include "myScene.h"
#include "cocostudio/CocoStudio.h"
#include "ui/CocosGUI.h"
USING_NS_CC;
using namespace cocostudio::timeline;
Scene *myScene::creatScene()
{
Scene *scene = Scene::create();
myScene *layer = myScene::create();
scene->addChild(layer);
return scene;
}
bool myScene::init()
{
Size win_size = Director::getInstance()->getWinSize();
// Test 1
// auto bn = ui::Button::create("ipadhd/CloseNormal.png",
// "ipadhd/CloseSelected.png",
// "ipadhd/CloseNormal.png");
// bn->setPosition(Vec2(win_size.width / 2, win_size.height / 2));
// bn->addClickEventListener(CC_CALLBACK_1(myScene::onBnClicked, this));
// addChild(bn);
// Test 2
// auto sp = Sprite::create("ipadhd/CloseNormal.png");
// sp->setPosition(Vec2(win_size.width / 2, win_size.height / 2));
// addChild(sp);
// auto listener = EventListenerTouchOneByOne::create();
// listener->setSwallowTouches(true);
// listener->onTouchBegan = [=](Touch* touch, Event* e) {
// Point pos = sp->getPosition();
// Size size = sp->getBoundingBox().size;
// Rect rect = Rect(pos.x - size.width / 2,
// pos.y - size.height / 2,
// size.width, size.height);
// pos = touch->getLocation();
// if (rect.containsPoint(pos)) {
// return true;
// }
// return false;
// };
// listener->onTouchEnded = [](Touch*, Event*) {
// Director::getInstance()->popScene();
// };
// getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, sp);
// Test 3
auto rootNode = CSLoader::createNode("SubScene.csb");
addChild(rootNode);
auto bn = static_cast<ui::Button*>(rootNode->getChildByName("Button"));
bn->addClickEventListener(CC_CALLBACK_1(myScene::onBnClicked, this));
return true;
}
void myScene::onBnClicked(Ref *pSender)
{
Director::getInstance()->popScene();
}
整个程序的效果就是点场景中唯一的按钮,利用pushScene与popScene切换场景,然后通过Xcode调试器观察内存使用变化。笔者照着两个场景中的场景切换按钮一阵狂点,切换N次场景后,Test1和Test2的内存占用都稳定的保持在16.5M,唯独Test3,场景每切换3次左右,内存占用就上升0.1M。
该BUG是在笔者做一个实际项目时发现的,比起Test3,笔者的实际项目中,每切换2、3次场景内存占用就上升2M,笔者一阵狂点,内存占用轻松突破300M,对于内存配备仅1G的iPadMini2来说,这种泄漏是相当危险的。
导致内存占用持续上升的原因是,在CSLoader中对资源进行了retain(),在随后的addChild()里,资源又被retain(),引用计数为2,但是在popScene()中资源只被release()一次,导致资源的引用计数最终变为1而不是0,占用内存自然不能被释放。
据说Cocos2d-x v3.3RC2以后的版本已经解决这个问题,即在CSLoader中不进行任何的retain()动作。