zoukankan      html  css  js  c++  java
  • cocos2dx

    ActionManager memory leak

    cocos2d-x3.7


    都3.7了还有这样的bug,真是好难过,不过还是好开源的,谁都可以贡献一下

    问题描述:

    当创建一个node,并让它run一个action的时,如果这个node没有添加到任何其它节点(即没有父节点),那么改node和action将一直不会被释放。


    原因:

    在node调用runAction时,会将动画交给ActionManager来管理,即调用ActionManager::addAction,看该函数的实现:

    void ActionManager::addAction(Action *action, Node *target, bool paused)
    {
        //...
        if (! element)
        {
            element = (tHashElement*)calloc(sizeof(*element), 1);
            element->paused = paused;
            target->retain();   //!!!watch out!!!
            element->target = target;
            HASH_ADD_PTR(_targets, target, element);
        }
    	//...
    

    注意这里会把node给retain一次,那它是在哪里release的呢,看下面:

    void ActionManager::update(float dt)
    {
    	//...
    	elt = (tHashElement*)(elt->hh.next);
    	if (_currentTargetSalvaged && _currentTarget->actions->num == 0)
    	{
    		deleteHashElement(_currentTarget);
    	}
    	//...
    }
    void ActionManager::deleteHashElement(tHashElement *element)
    {
        ccArrayFree(element->actions);
        HASH_DEL(_targets, element);
        element->target->release();   // release node
        free(element);
    }
    

    也就是说,当一个node在运行一个action时会被retain(referenceCount+1),在action运行完成后就会被release(referenceCount-1)。这么看起来没什么问题,但是当这个node不在running状态时,即没有添加到任何节点,通过create创建下一帧应该被自动释放,如果这时候给它运行了一个动画(ActionManager::addAction时第三个参数paused为true),再看update函数:

    void ActionManager::update(float dt)
    {
    	if (! _currentTarget->paused)  //动画不会被执行
    	{
    		//...
    	}
    	//...
    	elt = (tHashElement*)(elt->hh.next);
    	if (_currentTargetSalvaged && _currentTarget->actions->num == 0)
    	{
    		deleteHashElement(_currentTarget);
    	}
    	//...
    }
    

    此时动画一直不会执行,也就是说动画不会完成,那么actions->num不可能等于0,则该节点就一直不会被释放。


    解决方法:

    void ActionManager::update(float dt)
    {
    	//...
    	elt = (tHashElement*)(elt->hh.next);
    	if (_currentTargetSalvaged && _currentTarget->actions->num == 0)
    	{
    		deleteHashElement(_currentTarget);
    	}
    	//if some node refrence 'target', it's refrence count >= 2 (issues #14050)
    	else if (_currentTarget->target->getReferenceCount() == 1)
    	{
    		deleteHashElement(_currentTarget);
    	}
    	//...
    }
    

    那么问题来了:为什么会有这样的行为呢——创建一个node,不加到任何节点,还给它run一个action?
    这里解释过一遍了:https://github.com/cocos2d/cocos2d-x/pull/14090

  • 相关阅读:
    linux下创建virtualenv时指定python版本
    Centos7系统如何不重启系统识别新添加的硬盘?
    centos7系统下hostname解析
    Linux之shell脚本for、while、case语句的高级用法
    Linux自制编译内核
    Centos7系统详细的启动流程
    cpio的用法
    Linux之删除带有空格的文件(而不是目录)
    Linux之特殊的环境变量IFS以及如何删除带有空格的目录
    zabbix使用自定义脚本监控内存
  • 原文地址:https://www.cnblogs.com/songcf/p/4885651.html
Copyright © 2011-2022 走看看