سؤال

See [Solution]


FileReference.load(); does not have a function to unload, just as there is new Loader ().unload();.

Must be a "BUG" from Flash or FileReference needs improvement, type in a new version add a function like this: FileReference.unload();

Or am I mistaken and exists a SOLUTION?

I tried to set "NULL" to a variable of type FileReference, but clearly this does not work for the Flash works with GC (garbage collector), but this is not the focus of the question.

The problem is that a lot of memory when loading multiple files with new FileReferenceList is necessary, but I can not free memory after the process.

How to free memory after use of FileRerence?

See my code:

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;
        }
    }
}
هل كانت مفيدة؟

المحلول 2

I reached my goal, if I so did FileReferenceList.fileList[5] = null; (when the "sixth file" is not being used more) Flash memory immediately frees this specific FileReference.

In the others words:

This not work:

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

But this worked:

FileReferenceList.fileList[5] = null;

Worked on all Desktop/Plugins/PepperFlash.

See worked code:

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();
        }
    }
}

نصائح أخرى

Remove the event listeners before you null the listening object.

You could use weak references to let the listeners be removed when the object is Garbage Collected.

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

for example, in your LoadFile function:

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

should be:

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

Or you will have to remove them manually.

To do that you will need to move the event handlers into new named functions.

Also you will need an array for storing the references to listeners and listening objects, to be able to remove the listeners AFTER the listeners are not needed any more and BEFORE nulling the listening object.

PLEASE NOTE:

When you are testing it and watching the current memory usage, make sure to force the Garbage Collector when you feel the memory usage should have dropped by now, but it didn't.

GC kicks in when it wants and very not necessarily after something has been nulled on unloaded.

To be clear, I am only talking about forcing GC during the development/testing.

Even if you null every reference to an object, it won't be deleted immediately from the memory. You have to remove the event listeners aswell. Also, never use "unnamed" functions... it is harder to remove a listener when the event calls an unnamed function. So create a new function, and call that one. For example:

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

This will clean the memory.

The issue is a combination of all the things noted above.

  1. You do need to remove the event listener(s) manually. While its possible to use weak references its better if you make a habit of keeping track of the listeners you register and always unregister them properly. This way you can better avoid memory leaks(not quite a memory leak but has a similar effect) you didn't expect or weren't thinking about.

  2. You are creating event listeners in a loop and re-using the same function to handle all of them. If you do this you must somehow get a reference to the original loader and remove the event listener from it. I have no idea how you tried to incorporate Zhafur's answer but if you re-used file reference for each new file that will be the reason its still not working. Perhaps you can update you example above with the code you currently have so we can critique further.

  3. You should never force the gc(garbage collector), if you need to do this you have issues elsewhere you should solve instead as san.chez mentioned. Forcing the GC is a good way to see that you are creating too many objects too fast, if you see your memory usage go way down after forcing the GC you probably did this and should rewrite your code to be more efficient in its use of new.

Judging by the amount of memory you have consumed your either creating a ton of small files or a few extremely large ones, perhaps you can tell us more about that as well.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top