通过将实例从阶段中删除并将其置零来删除实例的函数不会将其从内存中删除

时间:2013-01-16 10:21:12

标签: actionscript-3 events event-listener

我遇到了一个用于删除实例并将其替换为另一个实例的函数的问题。基本上,无论如何,它都会将物品保存在记忆中。在对象内部,我有弱的侦听器,并且在删除之后我将其置零,但是我运行以检查它是否仍处于活动状态的函数告诉我它是(只是一个Event.ENTER_FRAME跟踪一些文本,带有弱链接)。 / p>

即使我从正在加载的实例中删除了所有内容,它仍然似乎留在内存中,根据我的描述它仍然存在。如何从内存中删除某些内容比将其从舞台中删除后将内容删除后更彻底?我没有看到什么吗?

这是功能:

private function loadArea(inputArea:String)
            {                      
                    //This is for a checker to make sure that areas only get loaded once.
                    currentRoom = inputArea;

                    //If the area currently loaded is not null, make it null now.
                    if(selectedArea != null) selectedArea = null;

                    //Null any data inside of the reference used to create the name of the new area.
                    areaReference = null;
                    //Grab the class using the input.
                    areaReference = getDefinitionByName(inputArea + "Area") as Class;

                    //Null the sprite used to house the class
                    areaSprite = null;
                    //Set the holder as a new instance of the desired class.
                    areaSprite = new areaReference() as Sprite;

                    //If the selected area is still not null for some reason,
                    if(selectedArea != null)
                    {
                            //Remove the area from the container...
                            areaContainer.removeChild(selectedArea);
                            //...and nullify it.
                            selectedArea = null;
                    }

                    //Set the current area as the newly created instance.
                    selectedArea = areaSprite;

                    //If the area is not the "Game", load in the assets one way,                   
                    if(inputArea != "Game") selectedArea.construct(areaAssets);
                    //otherwise do it another way.
                    else selectedArea.construct(newScreenData,apiServer,cdnServer,areaAssets);

                    //This is for a checker that fades out the screen, which it needs to fade back in soon.
                    newScreenData = null;

                    //While the container for areas has any areas inside of it, remove them.
                    while(areaContainer.numChildren) areaContainer.removeChildAt(0);

                    //...then add the new instance area to the container.
                    areaContainer.addChild(selectedArea);

                    //...then let all the parts of the game know that a new area has been laoded in.
                    Global.echoEvent.echo("gameBootUp","playAreaIn");
            }

3 个答案:

答案 0 :(得分:3)

当垃圾收集器找到并清除你的孤立实例时,实际上会释放内存。在此之前,您的内存使用情况将说明内存中有一个实例。没有办法强制垃圾收集,只调用System.gc()“指示”Flash运行它,它可能不服从。所以,你已经做了你必须做的事情,让它成为现实。

答案 1 :(得分:1)

删除包括stage和nulling对象在内的所有引用都是释放内存所需的全部内容。

如果对象没有被释放,那么你就会遗漏某些东西或做错事或不按顺序做事。

仔细检查您的代码,确保您确定引用对象的位置,以便删除它们。

查看示例代码:

if(selectedArea != null) selectedArea = null;

这里确保selectedArea为null。 但是在你再次测试selectedArea之后立即 (你知道它是null所以从不使用这个块)

if(selectedArea != null){
//Remove the area from the container...
areaContainer.removeChild(selectedArea);
//...and nullify it.
selectedArea = null;
}

答案 2 :(得分:0)

在每种语言中,它都非常难以“清除”记忆......甚至是HTML。话虽如此......试着减少你的记忆足迹。

Correct Null:
1. remove all event listeners
2. remove all children
3. remove all mapped/referenced methods/parameters
4. set the class object to null

在大多数情况下,这就是你需要做的全部,你做的方式将确定对象是否被清除。请考虑以下情况。

你有一个自定义精灵类(MEMORY FOOTPRINT#1),它有一个映射属性(当一个类对象引用另一个时,就会发生映射)。将一个对象映射/引用到另一个对象后= MEMORY FOOTPRINT#2。添加事件= MEMORY FOOTPRINT#3等等。

自定义精灵

import flash.display.Sprite;

class CustomSprite extends Sprite{

    private var _mappedProperty:Object;

    public function addMapping(map:Object):void{
        _mappedProperty = map;
    }

    public function finalize():void{
        _mappedProperty = null;
    }
}

假设我们在许多其他方法中使用CustomSprite,让我们看一些删除ojbect的常用方法。

INCORRECT - 在这种情况下,[objToRemove]未设置为null以释放其内存:

var objToRemove:CustomSprite = new CustomSprite;

function doSomething(referenceObj:CustomSprite):void{

    var methodObj:CustomSprite = referenceObj;

    //CRAZY LINES OF CODE

    methodObj = null;       //frees memory from [doSomething::methodObj]
    referenceObj = null;    //frees memory from [doSomething::referenceObj]

    //objToRemove is not cleared and will remain in memory
}

INCORRECT - 在这种情况下[objToRemove]有一个引用对象,因此在删除引用之前它不会被清除:

var objToRemove:CustomSprite = new CustomSprite;
var mappedObject:Sprite = new Sprite;

objToRemove.addMapping(mappedObject);       
objToRemove.addEventListener(Event.ENTER_FRAME,onEnterFrame);

//CRAZY LINES OF CODE

//remove all children
while(objToRemove.numChildren > 0){
    objToRemove.removeChildAt(0);
}

//remove all event listeners
objToRemove.removeEventListener(Event.ENTER_FRAME,onEnterFrame);

//this will NOT work
objToRemove = null;

//reason is objToRemove has a reference object of [mappedObject]
//[mappedObject] is not a child so it needs to be removed manually
//from WHITIN the CustomSprite class using [CustomSprite::finalize()]

好吧......呼吸......正确的方法实际上很简单。

CORRECT - 这里我们使用[Dynamic]对象而不是[Static]类对象,这被认为是对象映射:

//think of this as a global list of objects
var objPool:Dictionary = new Dictionary;

//create a pool reference
objPool['poolObj'] = new CustomSprite;

//CRAZY LINES OF CODE;

//do the normal [null] process

//both of these will work
objPool['poolObj'] = null;
//or
delete objPool['poolObj'];

超级高级正确 - 没有提供示例,我必须重新开始工作大声笑......

1. Take a ByteArray clone of the class
2. User a Loader to construct the ByteArray as the class, rather than using "new"
3. When finished... unload/remove the loader
4. EVERYTHING will clear... thats how a Loader works! 
(Not getting into why and how... too long of an explanation)

虽然这完美无瑕......但在工作环境中并未普遍接受或建议。