转载请注明: 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. Python中的raw_input()和input()

    raw_input()和input()都是python中的内建函数,用于读取控制台用户的输入,但有所区别: [nr@localhost conf]$ python Python 2.7.5 (defa ...

  2. 如何删除git远程分支(转)

    1,在开发过程中,大家在远程创建了许多分支,有些是无用的,该如何删除呢,可以参考下面的方法. 如果不再需要某个远程分支了,比如搞定了某个特性并把它合并进了远程的 master 分支(或任何其他存放 稳 ...

  3. supervisor 的使用

    1.通过yum安装 supervisor: 2.supervisorctl 查看状态: 3.supervisor.d 下查看配置文件,修改命令和日志目录 4.tail -f /var/log/supe ...

  4. <转>MYSQL数据库数据拆分之分库分表总结

    数据存储演进思路一:单库单表 单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到. 数据存储演进思路二:单库多表 随着用户数量的 ...

  5. linux中getmntent setmntent endmntent 用法例子

    mntent 结构是在 <mntent.h> 中定义,如下:               struct mntent {                      char    *mnt ...

  6. 【ios开发之疑难杂症】xcode运行出现SpringBoard 无法启动应用程序(错误:7)

    问题:xcode运行出现SpringBoard 无法启动应用程序(错误:7) 解决方案: 重启模拟器

  7. 用LR录制文件下载并随机产生文件名

    用LR录制文件下载并随机产生文件名 {H.IY:X.Tn0 8h&~-D|6fV0Action()51Testing软件测试网GE$nV}s,R{51Testing软件测试网 }9sUS'q  ...

  8. 16.Spark Streaming源码解读之数据清理机制解析

    原创文章,转载请注明:转载自 听风居士博客(http://www.cnblogs.com/zhouyf/) 本期内容: 一.Spark Streaming 数据清理总览 二.Spark Streami ...

  9. BFS迷宫搜索路径

    #include<graphics.h> #include<stdlib.h> #include<conio.h> #include<time.h> # ...

  10. 转:使用python的Flask实现一个RESTful API服务器端

    提示:可以学习一下flask框架中对于密码进行校验的部分.封装了太多操作. 最近这些年,REST已经成为web services和APIs的标准架构,很多APP的架构基本上是使用RESTful的形式了 ...