【问题标题】:How to free memory after use of FileRerence?使用 FileRerence 后如何释放内存?
【发布时间】:2014-03-29 23:22:04
【问题描述】:

见 [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;
        }
    }
}

【问题讨论】:

  • 你试过unloadAndStop(true)吗?
  • @SeanFujiwara 不起作用
  • System.gc() 仅用于测试/调试
  • @san.chez 我做了你说的一切(忽略“System.gc”),但似乎没有任何效果。
  • 您是否尝试过弱引用或手动删除事件监听器?请仔细阅读我的回答

标签: actionscript-3 flash memory actionscript filereference


【解决方案1】:

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

当对象被垃圾回收时,您可以使用弱引用来移除侦听器。

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

例如,在您的 LoadFile 函数中:

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

应该是:

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

否则您将不得不手动删除它们。

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

您还需要一个数组来存储对侦听器和侦听对象的引用,以便能够在不再需要侦听器之后以及在侦听对象清空之前删除侦听器。

请注意:

当您测试它并查看当前内存使用情况时,请确保在您认为内存使用量现在应该已经下降但没有下降时强制垃圾收集器。

GC 会在它需要的时候启动,而不一定是在某些东西在卸载时被清空之后。

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

【讨论】:

  • 你试过强制gc吗?如果是的话,有什么不同吗?
  • 不应该强制 GC 清理,GC 会自动清理...你必须对对象的每个引用都清空,这样 GC 才会知道你不再使用该实例。
  • @Zhafur,完全同意,但我的意思是:强制 gc 只是为了检查它是否还没有被 gc 清除(!)。
  • 添加了一个答案,基本上是你所说的,但有一个例子。
  • @Zhafur 我尽我所能设置了null,然后使用了GC,但没有用。还是忘记设置?
【解决方案2】:

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

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

这将清理内存。

【讨论】:

  • 因为您希望 GC 立即清理内存。它不会发生。 GC 不会立即清理内存。老实说,您不必担心内存使用情况,如果您按照我们所说的进行,将引用设置为 null 并删除事件侦听器,那么您的程序中就不会出现任何内存泄漏。
  • @san.chez,感谢您的编辑,已经很晚了,我把代码搞砸了! :)
  • 我将null 设置为“全部”,错过了什么地方?
  • 您必须删除事件侦听器,并使用 NAMED 函数,请在您的问题中更新您的代码。
  • @san.chez 但我说,我试过了,但没有用...我编辑了我的问题...
【解决方案3】:

我达到了我的目标,如果我这样做了FileReferenceList.fileList[5] = null;(当“第六个文件”没有被更多使用时)闪存会立即释放这个特定的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();
        }
    }
}

【讨论】:

    【解决方案4】:

    问题是上述所有问题的综合。

    1. 您确实需要手动删除事件侦听器。虽然使用弱引用可能会更好,但如果您养成跟踪您注册的听众并始终正确取消注册的习惯。这样可以更好地避免您没有预料到或没有考虑到的内存泄漏(不是完全的内存泄漏,但具有类似的效果)。

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

    3. 你不应该强制 gc(垃圾收集器),如果你需要这样做,你应该在其他地方解决问题,而不是像 san.chez 提到的那样。强制 GC 是一个很好的方法来查看你创建太多对象的速度太快,如果你看到你的内存使用在强制 GC 后大幅下降,你可能这样做了,应该重写你的代码以更有效地使用 new .

    根据您创建大量小文件或一些非常大的文件所消耗的内存量来判断,也许您也可以告诉我们更多相关信息。

    【讨论】:

    • 1 - 我已经这样做了,它与问题有关,问题在于“filerefence.load()”,无论是否有事件。 / 2 - 我使用包和类来实现这一点。但是要解决问题,因为问题是FileReference。 / 3 - 我编辑了代码,看看它是如何(有问题的)。 -- 我再次重申这个问题只发生在FileReference.load。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-29
    • 1970-01-01
    • 2020-05-21
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多