#apache-flex #memory-leaks #flex4 #profiling
#apache-гибкий #утечки памяти #flex4 #профилирование
Вопрос:
В моем приложении происходит утечка визуального компонента под названием GraphViewer. Каждый раз, когда пользователь изменяет графики, создается новый просмотрщик, а старый удаляется со сцены и отбрасывается. Тем не менее, память, похоже, протекает. Когда я использую профилировщик Flex для отслеживания зависших объектов, это показывает, что экземпляры GraphViewer действительно протекают, но когда я проверяю ссылки на объекты зависших зрителей, я вижу, что все они (кроме одного) имеют 0 путей к корню GC.
Я делаю снимок памяти после GC, а затем изменяю график (создаю новый просмотрщик) N раз. Затем я выполняю GC, делаю еще один снимок и смотрю на зависшие объекты. Я вижу, что N объектов GraphViewer слоняются без дела, но N-1 из них на самом деле имеют 0 путей, и только у одного есть что-либо, на самом деле ссылающееся на него.
Почему профилировщик Flex показывает объекты как зависшие, когда к ним нельзя получить доступ из корня GC? Надежен ли профилировщик Flex?
Ответ №1:
Во-первых, зачем вам нужно создавать новый экземпляр вашего компонента при поступлении новых данных? Кажется немного расточительным. Лучше повторно использовать экземпляр, чем создавать новый.
Во-вторых, трудно ответить на ваш вопрос без кода, но часто причина, по которой компонент представления хранится в памяти, заключается в том, что у кого-то либо все еще есть ссылка на него, либо прослушиватель событий не был очищен должным образом.
И, наконец, в течение некоторого времени в GC была известная ошибка (хотя я не тестировал ее в последнее время; прошло около года с тех пор, как я смог воспроизвести), когда большие «острова» памяти (представьте себе очень большой модуль) не будут очищаться должным образом, потому что алгоритм обхода для GC не поймет, что он отключен от остальных. Чтобы облегчить это, вы можете захотеть реализовать интерфейс IDisposable, в котором ваше «родительское» представление вызывает функцию destroy перед удалением со сцены (которая затем распространяется по всему компоненту, и ее дочерние элементы также подлежат уничтожению).
Удачи.
Комментарии:
1. Чтобы повторить и сосредоточиться на части ответа J_A_X, проверьте свои прослушиватели событий. Для каждого экземпляра, к которому вы добавляете EventListener, убедитесь, что removeEventListener вызывается перед уничтожением объекта. В моих проектах это, как правило, самый распространенный источник утечек.
2. Ситуация, которую я описал, является упрощением реального проекта. Это очень сложный пользовательский интерфейс с сотнями рекурсивных компонентов. Не хотел вдаваться в это здесь. Но суть в том, что я фактически использую событие Remove для очистки ссылок на эти объекты при каждом изменении модели. Если это ошибка GC, то, я думаю, у меня нет выбора, кроме как повторно использовать экземпляры. Но ручное освобождение всех ссылок в проекте просто безумно подвержено ошибкам и не может быть решением… (для чего, черт возьми, нужен GC, верно?). Итак, мне просто интересно, сталкивался ли кто-нибудь с этим явлением с 0 путями.
3. Кроме того, поиск всех addEventListeners и проверка того, что removeEventListener вызывается для каждого из них, даже если на элементы нет ссылок, не решит проблему для всех этих слушателей на основе mxml (или вы предлагаете, чтобы я каким-то образом их тоже выпустил)? Я просто отказываюсь верить, что Flash GC настолько ужасен .. 🙂
4. GC предназначен для очистки, но он не может устранить плохую разработку. Зачем вам в любом случае создавать новый экземпляр каждый раз? Это расточительно и бесполезно, особенно если ваш компонент тяжелый (что звучит так, как будто это так). Мне кажется, что ваша проблема заключается в неисправной архитектуре / коде больше, чем просто «Позвольте GC справиться с этим». Нет GC, который был бы надежен.
5. Прослушиватели на основе MXML автоматически очищаются после удаления со сцены. Опять же, я никогда не видел проблемы с этой конкретной проблемой. Если что-то и случилось, то это проблема с вашим кодом.