转载请注明: http://blog.csdn.net/herm_lib/article/details/9316601

项目中用到了cocos2dx和box2d,cocos2dx的内存是基于引用计数的,新建的内存一般加到一个自动的内存回收池中;而box2d的对象,是直接new/delete。

基于引用计数的对象和基于new/delete对象生命周期的结束是不一样的,前者有时比后者延后一帧(或者一个逻辑循环)才被删除。看一下实际遇到问题的代码。

class GameLayer : public cocos2d::CCLayer
{
public:
GameLayer();
~GameLayer(); static GameLayer* create();
private:
virtual void onEnter();
private:
// static b2World* m_phyWorld;
b2World* m_phyWorld;
}; // b2World* GameLayer::m_phyWorld = nullptr; GameLayer::GameLayer()
{
m_phyWorld = nullptr;
} GameLayer::~GameLayer()
{
delete m_phyWorld;
} GameLayer* GameLayer::create()
{
GameLayer* layer = new GameLayer;
layer->autorelease(); return layer;
} void GameLayer::onEnter()
{
// 删除上一次进关卡生成的物理对象
// delete m_phyWorld; m_phyWorld = new b2World(b2Vec2(0.0f, -10.0f));
MonsterSprite* monsterSprite = Monster::create(m_phyWorld);
    addChild(monsterSprite);

    CCLayer::onEnter();
}

GameLayer里生成一个b2World对象,同时也生成一个MonsterSprite 基于引用计数的对象,MonsterSprite是放到autorelease pool里,当GameLayer析构时removeChild, monster会被自动删除。再来看一下Monster做了什么。

class MonsterSprite : public cocos2d::CCSprite
{
private:
b2World* m_phyWorld;
b2Body* m_phyBody;
}; MonsterSprite* MonsterSprite::create(b2World* phyWorld)
{
MonsterSprite* monsterSprite = new MonsterSprite(phyWorld);
MonsterSprite->autorelease(); return MonsterSprite;
} MonsterSprite::MonsterSprite(b2World* phyWorld)
{
m_phyWorld = phyWorld;
m_phyBody = phyWorld->CreateBody(...);
} MonsterSprite::~MonsterSprite()
{
m_phyWorld->DestoryBody(m_phyBody);
}

MonsterSprite是一个cocos2d对象,他回创建b2Body, 在析构的时候,将这个body从b2World中删除。

代码看上去很清晰,貌似很正常。但跑起来,一般情况下,程序会在MonsterSprite::~MonsterSprite()的地方崩溃。我们分析一下,过程。
[1] 场景切换或者程序退出,GameLayer::~GameLayer()执行,这时候注意看delete m_phyWorld, b2World对象被删除;
[2] 执行CCLayer::~CCLayer(),  所有子节点被removeChild, MonsterSprite也被removeChild, MonsterSprite引用计数变为1了;
[3] 程序跑到下一帧,MonsterSprite被release, 执行MonsterSprite::~MonsterSprite,
         m_phyWorld->DestoryBody(m_phyBody);                   
      这个时候,m_phyWorld在上一帧就被删除了。
这种不同的内存管理方式,导致两个对象生命周期结束不一致。我想到了三种解决办法:
[1] 封装一下b2World,让的他内存管理方式和cocos2dx对象一致。
[2] MonsterSprite* monsterSprite = new MonsterSprite(phyWorld); 的时候,把monsterSprite保存起来,在GameLayer::~GameLayer()中,手动把monsterSprite中的b2Body      清除,不要等到析构的时候删除。
[3] 请看代码注释的地方,把b2World的生命周期拉长,GameLayer退出的时候,不删除;再次进入GameLayer的时候删除。这样做不会有内存泄露,也最简单。
    


引用计数的cocos2dx对象内存管理和直接new/delete box2d对象内存管理冲突的解决方法的更多相关文章

  1. Cocos2d-x 3.2编译生成Android程序出错Error running command, return code: 2的解决方法

    用Cocos2d-x 3.2正式版创建项目,结果使用cocos compile -p android编译生成APK程序,结果悲剧了,出现以下错误. Android NDK: Invalid APP_S ...

  2. 关于Cocos2d-x中掉帧导致游戏一卡一卡的网上一些的解决方法

    方法1 掉帧主要是setpostion引起的  因为每一帧每一个精灵都要set一次虽然不知道为什么会这样但是if(poX<1000&&pox>-100){     xx-& ...

  3. iOS内存管理系列之一:对象所有权与引用计数

    当一个所有者(owner,其本身可以是任何一个Objective-C对象)做了以下某个动作时,它拥有对一个对象的所有权(ownership): 1. 创建一个对象.包括使用任何名称中包含“alloc” ...

  4. Objective-C内存管理之引用计数

    初学者在学习Objective-c的时候,很容易在内存管理这一部分陷入混乱状态,很大一部分原因是没有弄清楚引用计数的原理,搞不明白对象的引用数量,这样就当然无法彻底释放对象的内存了,苹果官方文档在内存 ...

  5. OC基础15:内存管理和自动引用计数

    "OC基础"这个分类的文章是我在自学Stephen G.Kochan的<Objective-C程序设计第6版>过程中的笔记. 1.什么是ARC? (1).ARC全名为A ...

  6. cocos2D-x 3.5 引擎解析之--引用计数(Ref),自己主动释放池(PoolManager),自己主动释放池管理器( AutoreleasePool)

    #include <CCRef.h> Ref is used for reference count manangement. If a classinherits from Ref. C ...

  7. 初步swift语言学习笔记6(ARC-自己主动引用计数,内存管理)

    笔者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/31824179 转载请注明出处 假设认为文章对你有所帮助.请通过留言 ...

  8. swift内存管理中的引用计数

    在swift中,每一个对象都有生命周期,当生命周期结束会调用deinit()函数进行释放内存空间. 观察这一段代码: class Person{ var name: String var pet: P ...

  9. iOS内存管理机制解析之MRC手动引用计数机制

    前言: iOS的内存管理机制ARC和MRC是程序猿參加面试基本必问的问题,也是考察一个iOS基本功是 否扎实的关键,这样深入理解内存管理机制的重要性就不言而喻了. iOS内存管理机制发展史 iOS 5 ...

随机推荐

  1. Apache虚拟主机配置(多个域名访问多个目录)(转)

    Apache虚拟主机配置(多个域名访问多个目录) 为了方便管理虚拟主机,我决定使用一种方法,那就是修改httpd-vhosts.conf文件. 第一步首先要使扩展文件httpd-vhosts.conf ...

  2. 9.Python3标准库--数据压缩与归档

    ''' 尽管现代计算机系统的存储能力日益增长,但生成数据的增长是永无休止的. 无损(lossless)压缩算法以压缩或解压缩数据花费的时间来换取存储数据所需要的空间,以弥补存储能力的不足. Pytho ...

  3. 守护进程daemon函数

    #include  <unistd.h> int daemon(int nochdir,int noclose) 在创建精灵进程的时候,往往需要将精灵进程的工作目录修改为"/&q ...

  4. IEnumerable的几个简单用法

    咋一看到IEnumerable这个接口,我们可能会觉得很神奇,在一般的编程时,基本上我们是想不到去用它的,可是,俗话说得好,存在便是道理,那么,它对我们来说,能够带来哪些奇妙的事情呢? 要想弄懂它,我 ...

  5. [loj6039]「雅礼集训 2017 Day5」珠宝 dp+决策单调性+分治

    https://loj.ac/problem/6039 我们设dp[i][j]表示考虑所有价值小于等于i的物品,带了j块钱的最大吸引力. 对于ci相同的物品,我们一定是从大到小选k个物品,又发现最大的 ...

  6. pymongo的一些操作

    参考:http://www.yiibai.com/mongodb/mongodb_drop_collection.html http://www.cnblogs.com/zhouxuchen/p/55 ...

  7. Asp.net MVC CSS/Javascript Bundle 配置文件

    Asp.net mvc 中使用 Web Optimization 可以合并.压缩JS和CSS文件,但是每次修改都要改代码 ~/App_Start/BundleConfig.cs ,遂有了将它挪到配置文 ...

  8. OOD沉思录 --- 面向动作与面向对象 --- 避免泛滥成灾的类

    3.7 从设计中取出不需要的类 只有Get/Set方法的类不算是一个必要的类,Get/Set方法也不算是有意义的行为.这种类降级为属性更加合适. 3.8 去除系统外部的类 如果一个类只调用系统领域的方 ...

  9. heartbeat与keepalived的区别

    Heartbeat与Keepalived的区别 Keepalived使用的vrrp协议方式,虚拟路由冗余协议 (Virtual Router Redundancy Protocol,简称VRRP):H ...

  10. NEO4j简单入门

    Neo4j是: 一个开源 无Schema 没有SQL 图形数据库 图形数据库也称为图形数据库管理系统或GDBMS. Neo4j的官方网站:http://www.neo4j.org Neo4j的优点 它 ...