В чем заключаются преимущества (недостатки) использования слабых ссылок в EventListeners в AS3? - PullRequest
4 голосов
/ 05 августа 2009

Я изучал actionScript 3 за последний месяц или около того, и недавно столкнулся с проблемой, когда объект продолжал делать что-то после того, как думал, что его убрали. Я понял, что проблема была вызвана прослушивателем событий, использующим по умолчанию useWeakReference = false, и мне интересно, почему это по умолчанию. в чем преимущество не использовать слабую ссылку? и почему это по умолчанию? мне кажется, что в целом вы хотели бы использовать слабые ссылки, поэтому я должен что-то упустить.

Спасибо, -Ted

Ответы [ 4 ]

6 голосов
/ 06 августа 2009

Дело в том, что слабые ссылки стоят дорого ... они медленнее и занимают больше места ... вот код теста:

package {
    //{ region imports
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.EventDispatcher;
        import flash.system.System;
        import flash.utils.*;
    //} endregion
    public class Main extends Sprite {      
        public function Main():void {
            switch (0) {
                case 0: this.benchmarkDispatchers(false); break;
                case 1: this.benchmarkDispatchers(true); break;
                case 2: this.benchmarkDictionaries(false); break;
                case 3: this.benchmarkDictionaries(true); break;        
            }
        }
        private function benchmarkDictionaries(weakKeys:Boolean, size:uint = 1000000):void {
            var a:Array = [];
            for (var i:int = 0; i < size; i++) 
                a.push( { "foo":i } );

            var d:Dictionary = new Dictionary(weakKeys);
            var start:int = getTimer();
            var mem0:int = System.totalMemory;

            for (var j:int = 0; j < size; j++) 
                d[a[j]] = j;
            trace("adding "+size+" keys took "+(getTimer()-start)+" msecs and "+(System.totalMemory-mem0)+" B of memory with weakKeys == "+weakKeys);                           
        }
        private function benchmarkDispatchers(weakRef:Boolean, size:uint = 100000):void {
            var a:Array = [];
            var f:Function = function (i:*):Function {
                return function ():void { i; }
            }
            for (var i:int = 0; i < size; i++) 
                a.push( f(i) );
            var e:EventDispatcher = new EventDispatcher();
            var start:int = getTimer();
            var mem0:uint = System.totalMemory;
            for (var j:int = 0; j < size; j++) 
                e.addEventListener("foo", a[j], false, 0, weakRef);
            trace("adding " + size + " event handlers took " + (getTimer() - start) + " msecs and " + (System.totalMemory - mem0) + " B of memory with weakKeys == " + weakRef);
        }
    }
}  

это то, что я получаю на своей машине:

adding 100000 event handlers took 679 msecs and 6922240 B of memory with weakKeys == false
adding 100000 event handlers took 1348 msecs and 13606912 B of memory with weakKeys == true
adding 1000000 keys took 283 msecs and 16781312 B of memory with weakKeys == false
adding 1000000 keys took 906 msecs and 42164224 B of memory with weakKeys == true

результаты являются немного более радикальными для словарей, скорее всего потому, что в них нет вызовов ActionScript, связанных со временем, и поскольку некоторые накладные расходы на хранение при регистрации обработчика событий уменьшают разницу между необходимой памятью (как вы можете видеть, это 69 байт обработчик и 16 байт / ключ при сравнении слабых ссылок) ...

так что да, речь идет о производительности ... использование слабых ссылок не о крутом факте, что вам не нужно удалять слушателя, чтобы объект умер, если вы хотите иметь масштабируемую приложение, вам нужно делать такие вещи самостоятельно, и если вы хотите, чтобы это было на 100% надежно, вы не можете надеяться, что GC выполнит вашу работу, но вам нужно сделать уборку самостоятельно ... а также, если у вас хорошая иерархия в вашем приложении, вы, вероятно, не будете часто сталкиваться с этой проблемой ... в некотором смысле, это роскошь, если вы не хотите тратить время на правильную очистку объектов потому что проблемы, которые не могут быть решены без слабых ссылок, редки ... их следует использовать, когда они дают реальное преимущество, а не просто из-за лени ... я думаю, поэтому по умолчанию это ложно ...

надеюсь, что это помогает ...;)

Greetz

back2dos

2 голосов
/ 09 августа 2009

Слабые ссылки могут укусить вас при выполнении асинхронных операций, поскольку все, что не выполняется для привязанного к графу объектов, может быть в любой момент собрано мусором.

В частности, никогда не используйте слабые ссылки для обработчиков событий, которые являются функциями с областями действия:

function weakRefSample() : void
{
    var evntDispatcher : IEventDispatcher = new EventDispatcher();

    evntDispatcher.addEventListener(Event.COMPLETE, scopeHandler, false, 0, true);

    function scopedHandler(event : Event) : void
    {
    }
}

В приведенном выше примере есть две ошибки:

  • scopeHandler может быть собран, потому что там он не привязан к графу объектов
  • область выполнения weakRefSample может быть собрана, потому что ничто не требует его существования (ничто не использует scopedHandler), поэтому evntDispatcher может быть собран. Если evntDispatcher ожидал другого асинхронного события, его можно собрать до завершения этого события.
2 голосов
/ 06 августа 2009

Вы правы, обычно вы хотите использовать слабые ссылки, вероятно, в 99% случаев. Я думаю, что значение по умолчанию действительно должно быть установлено в true, но мы просто должны иметь дело с этим не так. Я предлагаю вам привыкнуть всегда использовать слабые ссылки, и вы избавите от нескольких головных болей и увидите некоторые преимущества в производительности, поскольку это помогает в управлении сборкой мусора.

Так когда бы вы хотели, чтобы это было ложным? По сути, в любое время, когда вы не хотите, чтобы вещи автоматически очищались, когда сборщик мусора решает, что вы больше не используете его. Такие ситуации редки, и когда придет время, вы, вероятно, просто узнаете.

ОДНАКО Это не может решить вашу проблему самостоятельно. Сборщик мусора работает только с непредсказуемыми интервалами, поэтому, даже если вы удалите все ссылки на объект, он все равно может обрабатывать эти события, пока он не будет очищен. Лучше всего удалить слушателей события, чтобы гарантировать, что они больше не будут срабатывать. Вы можете сделать это с помощью метода removeEventListener.

Удачи,

Тайлер.

0 голосов
/ 13 августа 2009

Я обнаружил, что экземпляры Timer со слабыми ссылочными прослушивателями иногда не запускают событие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...