2

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;
        }
    }
}
Community
  • 1
  • 1
Protomen
  • 9,471
  • 9
  • 57
  • 124

4 Answers4

6

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.

sanchez
  • 4,519
  • 3
  • 23
  • 53
  • 1
    Have you tried forcing gc? And if yes, does it make a difference? – sanchez Mar 29 '14 at 23:45
  • One should not force the GC to clean up, GC cleans up automatically... you have to null every reference to the object, so the GC knows that you no longer use that instance. – Zhafur Mar 30 '14 at 00:02
  • 1
    @Zhafur, totally agree, but I meant was: forcing the gc just to check if it hasn't been wiped out by gc yet(!). – sanchez Mar 30 '14 at 00:07
  • 1
    Added an answer, basically what you said, but with an example. – Zhafur Mar 30 '14 at 00:08
  • @Zhafur I set `null` in all that I could and then used GC and did not work. Or forgot to set somewhere? – Protomen Mar 30 '14 at 00:08
  • I update my answer. I moved to "packages" and "classes". I had to put in a zip code that was a bit long, but the code did not work. – Protomen Mar 30 '14 at 01:54
  • Excuse my ignorance, but would not be right `}, false, 0, true);` instead of `}, false, true);`? I update my question. – Protomen Mar 30 '14 at 02:21
  • Yes, absolutely right! :) priority=0, and do the same for test.contentLoaderInfo event listener – sanchez Mar 30 '14 at 02:35
  • Also add a temporary button somewhere, so you can click it to force GC , to test if week references(or removing listeners manually) helped. – sanchez Mar 30 '14 at 02:39
  • @san.chez I tried all of your tips and it did not work. The problem is really in the `FileReference.load`, which does not release the memory after use or "Flash" does not have a function to unload the FileReference (something like `FileReference.unload`), in other words the Flash needs improvement. If you disagree with me, then tell me what to do, please... tried everything... and nothing... Thanks for your efforts to help me. – Protomen Mar 31 '14 at 17:25
  • @GuilhermeNascimento try removing the listener for your FileReferenceList and nulling the FileReferenceList – sanchez Mar 31 '14 at 17:56
  • Yes, I tried and not working, the issue persists. I update my code (see question)... Thanks for your efforts – Protomen Mar 31 '14 at 18:22
  • @GuilhermeNascimento I am not sure if it will help you, but you could try installing monsterdebugger demonsterdebugger.com It might give you more info. – sanchez Mar 31 '14 at 19:16
  • Yes, this helped me, I redid the code, it releases almost all memory as MonsterDebbuger, see results: **1)** "Firefox/Safari (Flash plugin 12.0.0.77): Initiate with 9Mb, goes up 135Mb and ends with 17Mb." **2)** "Google Chrome (PepperFlash 12.0.0.70): Initiate with 12Mb, goes up 132Mb and ends with 17Mb." **3)** "Desktop(Player version 10/12 without run CS5): Initiate with 6Mb, goes up 185Mb and ends with 185Mb." – Protomen Apr 02 '14 at 17:44
  • Fixed type: @san.chez Thanks, MonsterDebugger helped me. We really have to take care with "GC". Maybe I'll buy Flash Builder (they told me he is perfect to detect causes this kind of problem) thank you for your detication! +1 for you – Protomen Apr 02 '14 at 18:51
  • Sorry to call you again, but I found something: With `FileReferenceList.fileList` if I so did `FileReferenceList.fileList[5] = null;` (when the "sixth file" is not being used more) Flash memory immediately frees this specific `FileReference`. This did the "FlashPlayer" to "desktop" also work. "Suddenly I was so happy". – Protomen Apr 02 '14 at 19:20
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();
        }
    }
}
Protomen
  • 9,471
  • 9
  • 57
  • 124
1

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.

sanchez
  • 4,519
  • 3
  • 23
  • 53
Zhafur
  • 1,626
  • 1
  • 13
  • 31
  • Because you expect the GC to instantly clean the memory. It won't happen. GC will NOT clean the memory immediately. You should not worry about memory usage to be honest, if you do what we said, setting the references to null and removing the event listeners, then there won't be any memory leak in your program. – Zhafur Mar 30 '14 at 00:10
  • @san.chez, thanks for the edit, it's quite late and I screwed the code up! :) – Zhafur Mar 30 '14 at 00:13
  • I seted `null` at "all", missed somewhere? – Protomen Mar 30 '14 at 00:13
  • You have to remove the event listeners, and use NAMED functions, please update your code in your question. – Zhafur Mar 30 '14 at 00:15
  • @san.chez But I said, I tried this and it did not work... I edited my question... – Protomen Mar 30 '14 at 00:21
  • NEVER write a function into another function... that's just a bad practice, and I still see some unnamed functions in your code. – Zhafur Mar 30 '14 at 00:25
  • I found that the problem is with `FileReference`, I edited my question, could you help me? – Protomen Mar 31 '14 at 17:25
0

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.

  • 1 - I've done this and it has to do with the problem, the problem is with the "filerefence.load ()", regardless of whether events (or not). / 2 - I used packages and classes for achieving this. However perciste the problem, because the problem is the FileReference. / 3 - I edited the code, see how it was (in question). -- And again I reiterate the problem only occurs with `FileReference.load`. – Protomen Mar 31 '14 at 12:15