Memory increases, GC does not collect.
My application is intended to run full-screen, on a touchscreen device, as an application for small children (pre-k).
The general operation is to present a series of scenarios, one by one, from a collection of separately developed swf files. (each swf file is a scenario). The child responds to the swf file, the swf file sends an event to the player, which performs an unloadAndStop() on the Loader object that loaded the swf. Then the next swf is loaded.
The problem we are seeing is that each swf file adds about 15-25 MB to the Workingset Private allocation of the AIR application (or the ADL.EXE runtime). Very little of this RAM is returned. After about 140 of these scenarios, the AIR runtime consumes about 1.6 GB of RAM. This, in itself, is not the problem - we could buy more RAM.
The problem is that the Loader crashes here, and takes the whole AIR runtime with it.
We also have a few "special purpose" swf files which are basically just wrappers around a s:VideoPlayer control, that plays a bindable file - .flv video, and the complete event fires the event that tells the AIR player to unloadAndStop the swf.
Since the video player took no manual intervention to test, I built a set of these to simulate a high load, and found that:
The .flv files are opened, but they are never closed. Since the s:VideoPlayer control is an MXML construct, there is no explicit way I can see to tell it to close the dang file when it's done. (it's not documented, anyway).
At exactly 32 video-swf items, the videos will continue to play, but there is no more audio.
At exactly 73 video-swf items, (seemingly regardless of the SIZE of the .flv file I select), the 73rd item crashes the Loader (and AIR player).
I supply unloadAndStop() with the (true) parameter. I follow it with a System.gc().
I explicitly remove ALL of my listeners. (in the AIR player application - I assume no control over items within the swf items that I am playing, since we assume we eventually may end up playing 3rd-party developed items; so we rely only on the return of a completion event, and a data structure).
I explicitly close() ALL of my audio streams. (at the AIR player level - not in the swfs.)
I explicitly stop() ALL of my timers.
My loader is instantiated in an element called "myLoaderContainer" - and after I receive my completion event, I do a myLoaderContainer.removeAllElements();
I have tried both the System.gc() call and the "unsupported" LocalConnection().connect('foo') call. both of these have zero effect. (in other words, I think there is probably no garbage to collect).
Still, I find it strange that nowhere, is it written, any kind of hint about how often garbage collection will do it's thing, and having graphed the flash.system.System.privateMemory; usage against all of my functions, and narrowed it down to my loader, and seeing that this allocation is never reclaimed, even on loader.unloadAndStop(true); - I wonder exactly what is the (true) parameter for, in that method?
I don't know what else I am supposed to do to force my Loader to *actually* unloadAndStop().
One would think that unloadAndStop() would not mean: "cease all functioning, but continue to occupy memory until the parent application chokes on it's own heap."
I recompiled the memory leaking program using AIR 3.0 and the leak remains. However my previous description of the problem was incorrect. It's not a bytearray I'm using. It's just a normal array, of 9 floats. Now this array is is being updated in an event, on an indefinite basis (from hardware data provided by a separate process running as a socket server). The updating array is a class scope array. On each update the index restarts to zero (ie. it's not a ballooning array). However, each item of that updating array is then being redispatched in the context of another socket event (request events by another process), using socket.writeDouble() - also on an indefinite basis.
So while the array is being written in the context of one event, it's simultaneously being read in the context of another uncorrelated event.
My only theory is that the speed at which the array is being written/read (since only nine floats) is causing some overflow in the number of temporary arrays that might be generated to accomodate such abuse. And that maybe such temps are becomining lost to the gc - that pehaps the gc can't keep up with the abuse. But that's just me speculating what theorys I could test for workarounds.
In native code I'd use various thread controls (mutexes etc), to control read/writes on the async socket events, but here I'm somewhat at a loss as to how to otherwise control the data flow. Indeed I ended up rewriting the program in native code (c++) to get around the memory leak.