System.gc() and Mediator dispatch failure
Hello guys,
I've been using RL with web apps for a long time, all dandy.
Recently started experimenting with air 3.0 and android
development. I'm forcing System.gc() because i'm using a tonn of
images (there is no other way) and by the time regular GC would
sweep I would run out of mem (besides it doesn't sweep as good as
manual, for whatever reason...)....
Anyway, I noticed (and I don't manual gc often, just on app main view switches) that sometimes events get sort of unmapped even though i don't see that unmaplisteners being called. It seems like gc is picking those mappings as "free" objects. Am I doing something wrong or is it a bug ?
Thanks.
PS Took me a while to find the cause of this "unmapping", I'm wondering if its default weak reference "true". If i change it to "false" would it make listeners stuck in memory? From looking at code it shouldn't, but is it a good practice for RL to have listeners mapped with strong references?
Comments are currently closed for this discussion. You can start a new one.
Keyboard shortcuts
Generic
? | Show this help |
---|---|
ESC | Blurs the current field |
Comment Form
r | Focus the comment reply box |
---|---|
^ + ↩ | Submit the comment |
You can use Command ⌘
instead of Control ^
on Mac
1 Posted by Rost on 02 Dec, 2011 07:18 PM
Also I noticed that sometimes it would randomly "unmap" them as well, with regular GC, while i was using new "gc advice" (which by the way does not seem very efficient).
namely this command:
System.pauseForGCIfCollectionImminent();
Support Staff 2 Posted by Ondina D.F. on 04 Dec, 2011 01:14 PM
Hi Rost,
That’s an interesting situation!
I’m using System.pauseForGCIfCollectionImminent(0.10); in one of my AIR applications, and I haven't encountered such a problem yet. I also tried to call the method at different points in time and also called System.gc(), but I couldn’t reproduce the issue. The useWeakReference is by default set to true and I didn’t change that.
In my opinion forcing the garbage collection shouldn’t affect your code in unexpected ways, but as we all know FlashPlayer’s gc is a very strange thing;)
I’m not sure it will help you, but let’s take a look at how the mappings work.
This:
eventMap.mapListener(eventDispatcher, SomeModelEvent.DATA_UPDATED, onDataUpdated, SomeModelEvent, false, 0, true);
is the same as adding an event listener to the shared IEventDispatcher.
This:
eventMap.mapListener(view, SomeViewEvent.NEED_DATA, onNeedData, SomeViewEvent, false, 0, true);
is the same as registering an event listener object with an EventDispatcher object (the view component)
As long as eventDispatcher is not null or in the second case the view is not null, and the handler function isn’t an anonymous function, the System.gc() won’t affect them.
The “unmapping” doesn’t occur because of the useWeakReference.
In fact it happens only in 2 circumstances:
- either you do it manually:
eventMap.unmapListener(eventDispatcher, SomeModelEvent.DATA_UPDATED, onDataUpdated);
eventMap.unmapListener(view, SomeViewEvent.NEED_DATA, onNeedData);
which rl-internally will result in this:
EventMap.unmapListener(dispatcher, type, listener, eventClass, useCapture)
-or it happens automatically after the View has been removed from the display list:
MediatorMap.onViewRemoved()
MediatorMap.removeMediator()
Mediator.preRemove()
EventMap.unmapListener(dispatcher, type, listener, eventClass, useCapture)
Now let’s look at this:
mediatorMap.mapView(SomeView, SomeMediator, null, true, true);
The last 2 parameters are autoCreate:Boolean and autoRemove:Boolean, by default set to true.
If autoRemove is set to true then robotlegs will remove the mediator and remove all listeners registered through its eventMap.mapListener when its view is removed from stage.
So, I would check if the “unmappings” are related to Views that have been removed from stage, through drag and drop actions or changing view’s states or by using something like a ViewStack.
I’m sure you already know about this:
https://github.com/robotlegs/robotlegs-framework/wiki/Common-Proble...
and this:
https://github.com/robotlegs/robotlegs-framework/wiki/Common-Proble...
Also, note the last parameter oneshot in ICommandMap.mapEvent(eventType:String, commandClass:Class, eventClass:Class=null, oneshot:Boolean=false)
if it is set to true it will unmap the Class after execution
As I said, maybe you already know all this, but I’m mentioning them just in case;) And also because I don’t know exactly if you were referring to the eventMap.mapListener or to the commandMap.mapEvent.
If you still think something is wrong with rl, it would be good if you could show us a simplified use case where you can reproduce the issues.
So, since I’m out of ideas maybe someone else can contribute with more advice about rl and gc.
Ah, here a few links:
Discussions on this forum about gc.
http://knowledge.robotlegs.org/discussions/questions/255-lifecycle-...
http://knowledge.robotlegs.org/discussions/questions/127-addeventli...
Here an interesting article about gc:
http://gingerbinger.com/2010/07/actionscript-3-0-events-the-myth-of...
I'm interested in hearing about your findings.
Ondina
3 Posted by Rost on 05 Dec, 2011 11:10 PM
Thanks a ton, Ondina, this is very thorough.
My problem as it happens was quite simple and was rooted deep in the beginning of my development: I did not create a reference to my context, i just created it as "new" and I guess it was getting garbage-collected...
So, no I did not see those articles before, although I did check the rest against it and it seems ok, but this one point helped. Thanks a lot for all the explaining. As far as unmapping goes, my breakpoints did not indicate it was happening, so i guess when context was gone it would stop all bus communication.
PS How do you find System.pauseForGCIfCollectionImminent(); versus System.gc() ?
My app has massive amounts of grapghic data placed and removed (lists) and the prior method would still not mark or trigger gc for a lot of items. I was testing using the memory/fps stats monitor i found on the net (widely used by as3 community), the difference was huge, in fact with "pauseForGC" it would only clean instances that were reused (i used object pooling extensively). It may have been that i got references hanging but then forcing "gc()" wouldn't pick them up either....On desktop none of this matters but on mobile memory is of high value....
Support Staff 4 Posted by Ondina D.F. on 06 Dec, 2011 11:12 AM
“Thanks a ton, Ondina, this is very thorough.
My problem as it happens was quite simple and was rooted deep in the beginning of my development: I did not create a reference to my context, i just created it as "new" and I guess it was getting garbage-collected...”
Hey, you’re welcome :)
Sometimes, I like to think of the framework in 2 ways:
-The Context is the Heart of your Application (Body) and the shared eventDispatcher represents the Vessels, letting the Blood (events, signals) flow to and from different Organs (Classes), supplying oxygen and nutrients (Data) to them. Without a heart, the body dies.
-The Context is the Brain and the shared eventDispatcher is the nervous system sending signals from one cell to another. Without a Brain the wiring is broken.
I know, these analogies are a little bit too far-fetched and there is no one-to-one correspondence between a living organism and an application;) Anyway, the Context, which is the one providing the shared eventDispatcher, has to be kept alive and accessible for the entire application life cycle.
“How do you find System.pauseForGCIfCollectionImminent(); versus System.gc() ?”
I started using System.pauseForGCIfCollectionImminent(); in one application when it became available, but I’ve never compared it to System.gc(), so I don’t know which one works better. I can’t see the source code for those System methods, so I don’t really know what’s going on behind the scenes. Something (irrational) is telling me that System.pauseForGCIfCollectionImminent(); should be the preferred way.
GC and memory management are complicated matters!!
Here a few links that I found to be useful:
http://forums.puremvc.org/index.php?topic=1291.msg5959#msg5959
From one of the articles (http://www.craftymind.com/2008/04/09/kick-starting-the-garbage-coll...) :
“First off we learned that a call to System.gc() only does a mark OR a sweep on any given object, but not both in the same call. So in order to have the effect of releasing memory back to the OS, we needed to call it twice in a row. One call to mark any dereferenced objects and sweep away old marks, and the second to now sweep away marks from the first call.”
Not sure if reading all those articles will help you:)
But if you find a good solution, please let me know about it!
Ondina
5 Posted by Rost on 07 Dec, 2011 01:51 AM
Hey, the analogy is perfect. I wasn't considering "heart" to go away so easily though, also I other applications i've created (non-mobile), using RL didn't let "heart " go :).
But anyway, not hard to add another reference.
Big thanks for links, ive seen a bunch of them but some stuff is the reading i haven't done yet. As far as double gc(), i think its the thing of the past. Right its working with just a single pass. I'm tracking this stuff using a variety of memory monitors including system monitor of the device itself and it does show.
You are correct, the "pause" way is what is promoted as preferred way by adobe, but for some reason it acts very differently, and mainly I think because it is not marking objects aggresively. Even though "pause" method works better then none I'm going to keep using gc() for now to clean "levels" which I wouldn't consider an abuse since it happens rarely and mostly (since i use pooling) to cleanup some previously disposed and nullified bitmapdata (which i guess i wouldn't need to clean manually but so far I don't see system doing it for me).
Support Staff 6 Posted by Ondina D.F. on 07 Dec, 2011 12:30 PM
You’re welcome :)
I’m going to close the thread now. You can re-open it at anytime, if you want to continue this discussion.
P.S. for some unknown reasons your last 2 posts have landed in tender’s spam folder and I had to restore them manually in order to be visible. Maybe the spam filter doesn’t like your email address ;)
Ondina D.F. closed this discussion on 07 Dec, 2011 12:30 PM.