如何在使用FileRerence后释放内存?

时间:2014-03-29 23:22:04

标签: actionscript-3 flash memory actionscript filereference

见[Solution]


FileReference.load();没有卸载功能,就像new Loader ().unload();一样。

必须是来自Flash的“BUG”或FileReference需要改进,请输入新版本添加如下函数:FileReference.unload();

或者我错了并且存在解决方案?

我尝试将“NULL”设置为FileReference类型的变量,但显然这不适用于Flash与GC(垃圾收集器)一起使用,但这不是问题的重点。

问题是当用new FileReferenceList加载多个文件时需要大量内存,但是在此过程之后我无法释放内存。

如何在使用FileRerence后释放内存?

请参阅我的代码:

Main.as

package {
     import com.mainpackage.LoaderTestCase;

     import flash.net.FileReferenceList;
     import flash.net.FileReference;
     import flash.net.FileFilter;
     import flash.events.Event;
     import flash.display.MovieClip;

     public class Main extends MovieClip {
          private var listFiles:Array;
          private var allTypes:Array;
          private var fileRef:FileReferenceList;
          private var test:int;

          public function Main()
          {
               test = 0;
               listFiles     = [];
               allTypes     = [];
               fileRef          = new FileReferenceList();
               fileRef.addEventListener(Event.SELECT, select);

               fileRef.browse(allTypes);
          }

          private function select(e:Event):void
          {
               listFiles = fileRef.fileList;

               for(var i:uint=0, j:uint=listFiles.length; i<j; i++)
               {
                    insert(i);
               }
          }

          private function insert(c:int):void
          {
               var fire:LoaderTestCase = new LoaderTestCase(listFiles[c]);

               fire.destroy(function():void
               {
                    //Delete LoaderTestCase after timeout ???
                    fire = null;
                    test++;
                    if(test>=listFiles.length) {//Remove FileReference
                         fileRef.removeEventListener(Event.SELECT, select);
                         fileRef = null;

                         for(var i:uint=0, j:uint=listFiles.length; i<j; i++) {
                              listFiles[i] = null;
                         }
                         listFiles = null;

                         trace("Clear memory");
                    }
               });
          }
     }
}

LoaderTestCase.as

package com.mainpackage
{
    import flash.net.FileReference;
    import flash.events.Event;
    import flash.display.Loader;

    public class LoaderTestCase
    {
        private var file:FileReference;
        private var loader:Loader;
        private var callback:Function;

        public function LoaderTestCase(e:FileReference)
        {
            file = e;
            trace("OPEN: " + file.name);
            file.addEventListener(Event.COMPLETE, loadFile);
            file.load();
            e = null;
        }

        public function loadFile(e:Event):void
        {
            file.removeEventListener(Event.COMPLETE, loadFile);

            trace("LOAD: " + file.name);

            file    = null;
            e       = null;
            callback();
        }

        public function destroy(a:Function):void
        {
            callback = a;
        }
    }
}

4 个答案:

答案 0 :(得分:6)

在使侦听对象为空之前删除事件侦听器。

当对象是Garbage Collected时,您可以使用弱引用来删除侦听器。

object.addEventListener( ......, ......., false, 0, true );

例如,在你的LoadFile函数中:

        ...
        LoadFile(file);
    }
});
...

应该是:

        ...
        LoadFile(file);
    }
}, false, 0, true );
...

或者你必须手动删除它们。

为此,您需要将事件处理程序移动到新的命名函数中。

此外,您将需要一个数组来存储对侦听器和侦听对象的引用,以便能够在不再需要侦听器之后删除侦听器,并且在侦听对象为空之前。

请注意:

当您测试它并观察当前的内存使用情况时,请确保在您觉得内存使用率应该已经下降时强制使用垃圾收集器,但它没有。

GC会在需要时启动,并且非常不一定在卸载后被删除。

要说清楚,我只是在讨论在开发/测试期间强制GC。

答案 1 :(得分:1)

即使您对对象的每个引用都为null,也不会立即从内存中删除它。您还必须删除事件侦听器。此外,永远不要使用“未命名”函数......当事件调用未命名的函数时,更难删除侦听器。所以创建一个新函数,然后调用它。例如:

test.contentLoaderInfo.addEventListener(Event.COMPLETE, contentLoaderInfoComplete);
...
function contentLoaderInfoComplete(e:Event){
    test.contentLoaderInfo.removeEventListener(Event.COMPLETE, contentLoaderInfoComplete);
    test.unload();
    test = null;
}

这将清理内存。

答案 2 :(得分:1)

我达到目标,如果我这样做FileReferenceList.fileList[5] = null;(当#34;第六个文件&#34;没有被更多使用时)闪存会立即释放这个特定的FileReference

用其他词语:

这不起作用:

private var file:FileReference;
...
file = FileReferenceList.fileList[5];
...
file = null;

但这有效:

FileReferenceList.fileList[5] = null;

适用于所有桌面/插件/ PepperFlash。

查看工作代码:

package {
    import flash.net.FileReferenceList;
    import flash.net.FileReference;
    import flash.net.FileFilter;
    import flash.events.MouseEvent;
    import flash.events.Event;
    import flash.display.Sprite;

    public class Main extends Sprite
    {
        private var listFiles:Array;
        private var allTypes:Array;
        private var fileRef:FileReferenceList;
        private var tmpFile:FileReference;
        private var i:uint=0;
        private var j:uint=0;
        private var timer:uint;
        private var imageTypes:FileFilter;
        private var enable:Boolean;

        public function Main()
        {
            imageTypes   = new FileFilter(
                "Images (*.JPG;*.JPEG;*.JPE;)", "*.jpg; *.jpeg; *.jpe;"
            );
            listFiles   = [];
            allTypes    = [imageTypes];

            eventBrowse(true);
        }

        private function eventBrowse(a:Boolean):void
        {
            enable = a;
            if(a===true) {
                stage.addEventListener(MouseEvent.CLICK, browse);

                fileRef = new FileReferenceList();
                fileRef.addEventListener(Event.SELECT, select);
            } else {
                fileRef.removeEventListener(Event.SELECT, select);
                fileRef = null;

                stage.removeEventListener(MouseEvent.CLICK, browse);
            }
        }

        private function browse(e:MouseEvent):void
        {
            if(enable===true) {
                fileRef.browse(allTypes);
            }
        }

        private function select(e:Event):void
        {
            listFiles = fileRef.fileList;

            eventBrowse(false);

            i=0;
            j=listFiles.length;

            if(j>0) {
                loadNextFile();
            }
        }

        private function loadNextFile():void
        {
            if(!(i<j)) {
                listFiles = null;
                trace("Free memory???");
                trace("--------------");
                trace("listFiles:"+ listFiles);
                trace("allTypes:" + allTypes);
                trace("fileRef:" + fileRef);
                trace("tmpFile:" + tmpFile);
                trace("i:" + i);
                trace("j:" + j);
                trace("timer:" + timer);
                trace("--------------");
                eventBrowse(true);
                return;
            }

            tmpFile = listFiles[i];
            trace("Initiate load:" + tmpFile.name);
            tmpFile.addEventListener(Event.COMPLETE, loadedFile);
            tmpFile.load();
        }

        private function loadedFile(f:Event):void
        {
            trace(listFiles);
            trace("Finished load:" + tmpFile.name);
            tmpFile.removeEventListener(Event.COMPLETE, loadedFile);

            tmpFile = null;
            listFiles[i] = null;

            i++;
            loadNextFile();
        }
    }
}

答案 3 :(得分:0)

问题是上述所有事情的组合。

  1. 您需要手动删除事件侦听器。虽然可以使用弱引用,但如果你习惯跟踪你注册的监听器并且总是正确注销它们,那么它就更好了。通过这种方式,您可以更好地避免内存泄漏(不是内存泄漏,但具有类似的效果),您没有预料到或者没有想过。

  2. 您正在循环中创建事件侦听器并重新使用相同的函数来处理所有这些事件。如果你这样做,你必须以某种方式获得对原始加载器的引用并从中删除事件监听器。我不知道你是如何尝试整合Zhafur的答案,但如果你为每个新文件重新使用文件参考,那将是它仍然无法正常工作的原因。也许您可以使用当前的代码更新上面的示例,以便我们进一步批评。

  3. 你永远不应该强迫gc(垃圾收集器),如果你需要这样做,你应该解决其他地方的问题,而不是san.chez提到的。强制GC是一种很好的方法,可以看到你创建太多的对象太快,如果你看到你的内存使用率在强制GC之后就会下降你可能会这样做并且应该重写你的代码以便更有效地使用新的

  4. 根据您消耗的内存量来判断,无论是创建大量小文件还是创建一些非常大的文件,也许您可​​以告诉我们更多相关内容。