How to free memory after using a FileRerence?

2

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

Should be a Flash BUG or FileReference needs to be improved, type in a new version to add a function like this: FileReference.unload();

Or am I wrong and is there a SOLUTION?

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

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

How to free memory after using FileRerence ?

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;
        }
    }
}
    
asked by anonymous 31.03.2014 / 18:39

2 answers

3

I was able to reach my goal, I discovered something with FileReferenceList.fileList

If I do this FileReferenceList.fileList[5] = null; (when the "sixth file" is no longer being used) Flash immediately releases the memory of this FileReference specified.

What I mean by this is that if you do this Flash does not release memory:

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

But this frees the memory "immediately":

FileReferenceList.fileList[5] = null;

It worked in all, in Adobe Flash Professional, Plugins installed on the machine and PepperFlash (Chrome Plugin).

Code in operation:

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 (false === (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();
        }
    }
}
    
02.04.2014 / 21:56
2

This is not a bug . The Flash Player's Garbage Collector actually runs from unpredictable way. It is responsible for keeping the machine ram free and we have to take this into consideration.

Unfortunately, there is no way to free up machine memory instantly (with the exception of the BitmapData class that has a method called #), as soon as the Trash Collector is only executed when it actually needs to free memory and also, there is no control of this object by the Programmer but by the Flash Player's own VM.

The Adobe reference itself suggests / determines that for GC to "destroy" unused objects you set the instances to them as null , which most often activates it.

What might be happening with your code is that GC is not yet capable of capturing objects that are not instantiated because the object itself was loaded asynchronously through a Event , which makes it impossible to define null , since the only way to access it is by a method "only" e.currentTarget() .

It is not just a Flash peculiarity, as mentioned, there are other languages that use this same scheme. However, Flash is still far behind achieving that perfection.

I do not know what the final purpose of your application is after loading the files, but you could try loading them into the same ByteArray object, dividing each file by parts, saving and then generating the final file of each one and after , set this object to null .

Another way is for you to build a "Gambiarra", sending your current frame to a completely empty and non-functional (Like another Scene, for example), this usually activates GC . >     

02.04.2014 / 18:10