Компонент не собирает мусор

Я только что заметил странное поведение, глядя на свое приложение во Flash Profiler. Когда я нажимаю кнопку в своем TitleWindow, TitleWindow не собирает мусор после его удаления. Понятия не имею, почему это происходит.

Я создал небольшой пример приложения, так что вы можете попробовать его сами:

Main.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx" pageTitle="Memory Leak (Spark)">

    <fx:Script>
        <![CDATA[
            protected function openWindowBtn_clickHandler():void
            {
                removeAllElements();
                addElement(new ExampleView());
            }
        ]]>
    </fx:Script>

    <s:controlBarContent>
        <s:Button label="Open Window" id="openWindowBtn" click="openWindowBtn_clickHandler()"/>
    </s:controlBarContent>
</s:Application>

ExampleView.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%" title="Example View" close="closeHandler()">

    <fx:Script>
        <![CDATA[
            import mx.core.IVisualElementContainer;

            protected function closeHandler():void
            {
                var visualElementParent:IVisualElementContainer = parent as IVisualElementContainer;

                if (visualElementParent)
                    visualElementParent.removeElement(this);
                else
                    parent.removeChild(this);
            }
        ]]>
    </fx:Script>

    <s:layout>
        <s:VerticalLayout verticalAlign="middle" horizontalAlign="center"/>
    </s:layout>

    <s:Button id="doSomethingBtn" label="Click me!"/>
</s:TitleWindow>

Когда вы нажимаете «Открыть окно» и закрываете ExampleView, не нажимая «Click me!» нажмите кнопку, затем включится сборщик мусора и удалит ExampleView. Однако, когда вы нажимаете на «Щелкни меня!» а затем закройте ExampleView, ExampleView останется в памяти навсегда.

Мне не удалось найти в профилировщике ссылки, которые вызывают такое поведение. Я надеюсь, что кто-то знает решение этой проблемы, иначе Flex создаст много утечек памяти.


person Gerhard Schlager    schedule 18.10.2010    source источник
comment
После дальнейших тестов похоже, что это происходит только один раз. Итак, если вы выполните шаги (открытое окно, щелкните «Щелкните меня», закройте окно) три раза, только один экземпляр TitleWindow не будет собирать мусор.   -  person Gerhard Schlager    schedule 18.10.2010


Ответы (3)


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

О сборке мусора

Или взгляните на эту презентацию: Сборка мусора - Алекс Харуи


<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
           xmlns:mx="library://ns.adobe.com/flex/mx" pageTitle="Memory Leak (Spark)">

<fx:Script>
    <![CDATA[
        protected function openWindowBtn_clickHandler():void
        {
            removeAllElements();
            addElement(new ExampleView());
        }

        protected function button1_clickHandler(event:MouseEvent):void
        {
            var o:Object = new Object();
            System.gc();
        }

    ]]>
</fx:Script>

<s:controlBarContent>
    <s:Button label="Open Window" id="openWindowBtn" click="openWindowBtn_clickHandler()"/>
    <s:Button label="Force GC"  click="button1_clickHandler(event)"/>
</s:controlBarContent>
</s:Application>

Взгляните на это. Если вы нажмете кнопку «Force GC» несколько раз, он соберет ExampleWindow. В реальном приложении, которое что-то делает, это происходит без необходимости вызывать System.gc () (на самом деле, вызывать его не рекомендуется), но через некоторое время, поэтому вещи не исчезают, когда вы закончили с ними, они исчезают, когда вы закончите, и Flash Player решает, что их нужно очистить.

person Robert Bak    schedule 18.10.2010
comment
Спасибо за ссылки. Я это уже знал. Чтобы убедиться, я еще раз взглянул на них. Однако я не думаю, что сборщик мусора игнорирует эти экземпляры, даже если на них нет ссылок. Очевидно, что компоненты внутри TitleWindow (например, нажав кнопку Click me) могут предотвратить сборку мусора TitleWindows. Я просто не могу понять, почему это происходит. - person Gerhard Schlager; 18.10.2010
comment
Конечно ты прав. Сборщик мусора Flash Player собирает данные только тогда, когда это необходимо. Однако я убежден, что где-то там есть ошибка. Просто взгляните на созданную мной ошибку # SDK-28259. Вот простой пример, показывающий, как дочерний компонент, такой как TextInput, может предотвратить сборку мусора своего родителя. Я только что протестировал ваш способ принудительного включения сборщика мусора, и это не помогло. В любом случае, я отмечу это как ответ, поскольку вы предоставили кучу полезной информации / ссылок, и надеюсь, что мой отчет об ошибке не будет игнорироваться Adobe так, как многие другие. - person Gerhard Schlager; 20.10.2010
comment
Багтрекер Adobe был закрыт. Однако теперь проблему можно найти в багтрекере Apache по адресу # FLEX-25652. . - person Gerhard Schlager; 15.03.2013

Возможно, я ошибаюсь, но iirc EventListeners, добавленные в MXML, всегда создаются с сильной ссылкой, что предотвратит GC от GC.

Вы пробовали вручную добавить EventListener, задав для него слабую ссылку? Если вы посмотрите на список слушателей событий в отладчике, вы должны увидеть что-то вроде WeakMethodClosure, если он был добавлен со слабой ссылкой.

person Baelnorn    schedule 18.10.2010
comment
Сначала я подозревал то же самое. Итак, как вы можете видеть в примере, я удалил обработчики событий кнопок. Тем не менее, всякий раз, когда я нажимаю кнопку, TitleWindow не будет собирать мусор. Более того, кнопка, ссылающаяся на замыкание в родительском элементе, не должна быть проблемой. - person Gerhard Schlager; 18.10.2010
comment
@gertschi: Извините, я как-то неправильно понял первую кнопку за вторую. ‹_‹ Что происходит с closeHandler? Правильно ли собираются функция и переменные после запуска? Кроме этого, сейчас я не вижу ничего, что все еще содержало ссылку. В крайнем случае вы можете сообщить о проблеме и открыть ошибку в багтрекере Adobe. - person Baelnorn; 18.10.2010
comment
Спасибо, что намекнули на closeHandler. Я присмотрелся и обнаружил, что удаление TitleWindow из события закрытия TitleWindow (или любого другого события, которое запускается изнутри окна) не работает без утечки памяти при нажатии кнопки Click me. Удаление TitleWindow путем нажатия дополнительной кнопки на панели управления приложениями всегда позволяет сборщику мусора также удалить его из памяти. - person Gerhard Schlager; 18.10.2010
comment
Это определенно имеет какое-то отношение к дочерним компонентам контейнера, таким как Button или TextInput. Я создал ошибку в багтрекере Adobe: # SDK-28259. - person Gerhard Schlager; 19.10.2010

Похоже, что ExampleView не получает сборщик мусора, потому что каким-то образом добавляется EventListener при нажатии кнопки «Click Me». Лучший способ избежать этого - 1. добавить прослушиватель событий вручную в событие createComplete 2. Удалить EventListener в closeHandler 3. Удалить кнопку из контейнера и установить для нее значение null.

Теперь ExampleView будет обработан сборщиком мусора.

person user5073283    schedule 02.07.2015