zoukankan      html  css  js  c++  java
  • Cocos2d之Ref类与内存管理使用详解

    一、简介

    用C++和JAVA编写过程序的朋友一定会为两种语言不同的内存管理机制懊恼。JAVA程序运行在JVM之上,由JVM自动实现内存管理,开发者只管申请内存而不用手动释放内存。当JAVA中对象没有被任何引用变量(类似于C和C++的指针)引用时,JVM会将对象释放掉。C++和C一样,是编译后能够直接被操作系统执行的语言,没有虚拟机负责其内存管理,因此需要在程序中管理内存。本文主要介绍如何使用cocos2d提供的内存管理机制。

    Cocos2d-x借鉴了“引用计数”思想,实现了一定程度上的自动内存管理。cocos2d委托对象管理池PoolManager存放对象和释放对象资源,管理池释放对象的判据是对象的引用计数为0。

    二、Ref类

    Ref类实现了与cocos2d内存管理机制交互的接口,所有Ref的子类对象的内存能够被管理池自动管理。Ref类的接口如下:

    //////////////////////////////////////
    // 该方法能够增加Ref对象的引用计数
    void retain();
    
    /////////////////////////////////
    // 减少 Ref 对象的引用计数,
    // 如果计数减少到0,则对象被释放
    void release();
    
    ////////////////////////////////
    // 没有立即减少引用计数,
    // 而是在结束当前pool池时,减少Ref对象的引用计数
    // 如果计数减少到0,则对象被释放
    void autorelease();

    当实例化一个Ref类的子类时,调用该对象的retain方法能够使计数加1。下面看一下常用的Ref子类Scene类的create方法的实现原理:

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

    实例化Scene类后,立即调用autorelease方法,如果返回的ret被其它地方使用(也就是调用对象的retain方法使引用计数加1),那么在本次pool池结束后对象不会被销毁;如果返回的ret没有被使用,那么本次poo池结束后对象被销毁以防止内存溢出。

    ////////////////////////////////////////
    // 返回的ret被addChild方法使用
    // addChild内部会调用ret的retain方法使引用计数加1
    // 本次pool池结束后ret指向对象不会被释放
    this->addChild(Scene::create());    // create返回ret指针

    再举一些例子。

    ///////////////////////////////////////
    // __Array是Ref的子类
    // 必须显式调用retain方法,否则count方法出错
    // 因为array引用计数为0,pool结束后将其释放
    auto array = __Array::create();
    array.retain();
    ....
    array.count();  // 在上次pool结束后,比如按键回调中使用
    ///////////////////////////////////////
    // addObject方法能够显式调用sprite.retain(),
    // 所以对象不会被释放
    Sprite *sprite = Sprite::create();
    array.addObject(sprite);
    ....
    Sprite *sp = (Sprite*) array.getLastObject(); // 在上次pool结束后,比如按键回调中使用

    下面总结一下cocos2d管理内存的一些规则

    • 在使用Node节点对象的时候,addChild()方法能够隐式调用被添加节点的retain方法,removeChild()方法能够调用被移除对象的release方法。
    • 如果是__Array和__Dictionary等由coco2d的类,它们本身是Ref的子类,它们添加或者删除元素时能够相应地隐式调用retain和release方法。但前提是,__Array和__Dictionary的对象需要被retain以保证不被释放掉。
    • 如果不是上述的Ref子类对象,需要显式并且成对地调用retain和release方法。 
  • 相关阅读:
    图片的存储
    【已解决】如图,说我磁盘不够,看到var目录下有的个隐藏文件夹占了46G,不知道怎么删除
    Java 中时间处理SimpleDateFormat 中HH和hh的区别
    api的日志
    网页报警提示 This page includes a password or credit card input in a non-secure context. A warning has been added to the URL bar. For more information, see https://goo.gl/zmWq3m.
    Springboot项目中的favicon
    页面Header自适应屏幕
    Vue 日期下拉框
    VUE 单选下拉框Select中动态加载 默认选中第一个
    Vue 循环 [Vue warn]: Avoid using non-primitive value as key
  • 原文地址:https://www.cnblogs.com/chenshi/p/4082805.html
Copyright © 2011-2022 走看看