关于cocos2d-x内存管理及渲染过程

求大神帮忙,两个问题
第一 内存管理方面
类似于这种创建一个精灵
auto sprite = Sprite::create(“HelloWorld.png”);
这个create函数中会将指针autorelease掉,看书上说是下一帧开始前会释放掉内存,也就是说保存图片内容的内存会释放掉是吗?
那么下一帧,这个精灵所表现的内容应该没了,可是为什么还在场景中显示呢。

第二 渲染过程

我知道每一帧都会去渲染场景,根据节点树,因为对资源的加载等一般在onEnter等函数的初始化中
我想知道,是不是每一帧渲染都是去降这个onEnter函数去执行一次,要是不是这样的话,我理解不了这个渲染过程是如何进行的

是等所有资源加载好,然后不停的去渲染吗

不知道我表达的意思清楚没有,好困惑

每一帧渲染都是调用节点的draw函数,如果将要显示的图片加载到内存中了,那么可以绘制出来我能理解
可是在下一帧之前不是内存已经被释放掉了吗,为什么下一帧还能绘制出来?

下一帧释放掉意思是引用计数没有增加的情况下才释放掉,
但你调用了addChild方法引用计数增加所以不会被释放
onEnter 只会执行一次
碰到这种问题建议看下源码。
一目了然

autorelease 只是将对象放入一个对象池,下一帧将引用计数减一,如果引用计数为0,那么会被释放掉

之所以能绘制出来,没有释放时因为引用计数不为0,因为当sprite添加到显示列表时(实际代码是将sprite放入一个父节点的children容器,cocos2d::Vector),引用计数会增加1

既然addChild会让引用计数+1
那么算上初始化就是2
在下一帧会减1,后面引用计数就一直是1,所以一直存在是吗

那么当场景切换时,我需要将这个资源释放掉,是需要人为控制让他减1吗

还有个问题是,因为这里是一个精灵,精灵里面是纹理,我释放这个精灵资源,那么那么纹理会被释放吗,如果纹理没有释放,那么纹理该如何释放

我在网上看到说纹理的释放是需要靠人去控制

既然addChild会让引用计数+1
那么算上初始化就是2
在下一帧会减1,后面引用计数就一直是1,所以一直存在是吗

那么当场景切换时,我需要将这个资源释放掉,是需要人为控制让他减1吗

还有个问题是,因为这里是一个精灵,精灵里面是纹理,我释放这个精灵资源,那么那么纹理会被释放吗,如果纹理没有释放,那么纹理该如何释放

我在网上看到说纹理的释放是需要靠人去控制

我现在的理解是这样的,帮我看看对不对
create创建一个精灵时,引用计数+1,而且会调用autorelease,这个精灵会在下一帧前release,如果引用计数为0会被释放,但是通过addChild加入到节点树后,自身引用计数会+1,所以在下一帧前减1后,引用计数还是1,所以不会被释放,一般在onExit函数中,会removeAllChildrenWithCleanup(true),会释放节点树,让引用计数-1,所以会在下一帧时释放

而这个精灵所使用的纹理内存,会一直存放在内存中,需要人手动释放。

为什么都没人。。。。

其实这些问题都可以看源码知道的。
首先内存问题:
cocos2dx采用引用计数来管理内存,对象每次retain时引用计数+1,每次release时引用计数-1,当引用计数为0时,delete释放该对象。
继承于CCObject(Ref)的类在创建create的时候都会引用自动引用计数方法autorelease(将引用计数初始化为1),将创建的对象放入内存管理池中。
在下一帧渲染的时候就释放掉这个内存管理池,此时该被添加到内存管理池中的对象就会全部release一次(引用计数-1,引用计数为0就释放)。
所以当一个对象创建出来时,如果没有自身引用retain方法或者被其他对象管理(即添加为子对象,addchild,addobject等),就会在创建出来的下一帧释放掉。
addchild方法中其实也是使用retain方法,remove的时候引用release方法,父节点析构时也会调用子节点的release方法。
第二个纹理缓存问题:
auto sprite = Sprite::create(“HelloWorld.png”);
通过查看源码你会发现,引擎是会先先在TextureCache纹理缓存中查找HelloWorld.png的文件名对应的纹理,找不到该纹理的话再在源文件路径中查找该HelloWorld.png的文件,再将该文件的纹理添加到TextureCache纹理缓存中(下次再使用HelloWorld.png的图片时就不用再加载,从而降低内存的使用和提高渲染效率)。
即使你释放了这个精灵的对象,该纹理也会一直存放在纹理缓存中,以便下一次使用。
当然你也可以手动释放掉该纹理,使用Director::getInstance()->getTextureCache()->removeUnusedTextures(); 会释放当前所有引用计数为1的纹理,即目前没有被使用的纹理。比如新场景创建好后,可以使用此方法释放没有使用的纹理。
使用Director::getInstance()->getTextureCache()->removeTextureForKey(“HelloWorld.png”)释放特定的纹理

手动码代码,可能会出错,详情请查官方API

总结一下就是 纹理缓存,帧缓存之类的内存
是需要人为释放,而且释放的条件是引用计数为1

而从节点类继承下来的,是自身检查引用计数,当为0时去释放

是这个意思吗

引用计数为0删除内存可以理解,就是说这个节点已经被移除了

但是为什么清理纹理缓存 是清理引用计数为1的,为1表示这个纹理缓存没有被使用吗?

因为纹理缓存生成是没有autorelease吗 ,生成时,引用计数为1,如果一直为1,表示这个纹理没有被使用?

我们知道,一个继承于CCObject(Ref)的对象new出来的时候,该对象的引用计数设为1,
当精灵创建Sprite::create(“HelloWorld.png”);时在其内部调用addImage方法,把该纹理的引用计数做了+1处理,此时该纹理的引用计数为2.
当移除这个精灵的时候,引用计数会-1,这个时候引用计数为1。也就是说该纹理没有被使用。
此时你调用TextureCache::removeUnusedTextures方法。那这张纹理将从内存中移除。
但是如果有两个精灵同时使用了这张纹理,那该纹理的引用计数为3,必须两个精灵都移除后,才能释放内存。

详细一点的话就是TextureCache中有个CCDictionary字典容器m_pTextures,会把纹理和纹理对应的键值放到里面,使用的时候直接从该字典容器中根据键-值对应的纹理取出来。
建议不懂的话好好研究一下源码,顺着函数的调用追踪下去。