![]() |
|
||||||||||
|
|||||
|
Регистрация: Jul 2009
Адрес: Донецк
Сообщений: 25
|
Ситуация:
В моей игре главный герой перемещается постоянно вверх и ему на встречу попадаются монетки, которые он должен собирать. Монетки появляются на экран выше героя, пролетают мимо него, и только вылетев за экран, или попав в героя - удаляются. Так вот, столкнулся с проблемой. Если монеток будет много, штук 20 в секунду, например, то через несколько минут фпс начинает уверенно падать и игра начинает тормозить. Я сначала думал, что обьекты не полностью удаляются, остаются где-то в памяти и тормозят игру. Но выявить это оказывается не так просто. Моё решение: Первое что пришло в голову - проверить, удаляет ли Сборщик мусора мой обьект. Для этого я проверил удаление всех ссылок и событий на него, сделал в нём таймер, который раз в секунду делает trace('some text'). И действительно, через секунд 10 после исчезания монетки с экрана - trace - перестаёт выводится, следовательно я посчитал, что обьект удалён сборщиком. Причём, если вызвать сборщик мусора сразу после исчезания монеты с экрана, то trace - тоже сразу же перестаёт выводится, значит обьект по идее точно удаляется с помощью GC. Но тут начались странности. Странности: Попробовал специально оставить жесткую ссылку на обьект, присвоив его переменной tmp. Но вопреки моим ожиданиям, после пролёта монеты trace - перестал выводится всёравно, будто обьект удалился. В то же время если вызвать tmp.SomeFunction(), то эта функция успешно выполнится, будто обьект всё еще существует. o_O Подскажите, как проверить удалён ли обьект из памяти, почему в моём примере были такие странности? Какие инструменты чтобы применять проверить, существует ли обьект в памяти? Как вообще правильно удалять обьект? |
|
|||||
|
Так используйте пул объектов (монеток)! Мало того что Флешу приходится создавать ненужные экземпляры, так Вы его еще заставляете рыскать по дереву (DisplayList) в поисках объекта и удалять его. Монетка доходит до низа/героя - перемещаете её вверх за пределы Stage (y -= stage.width), нужно увеличить размер пула - array.push(new Coin()); иначе array.peek(); (:todo implement peek())
![]() |
|
|||||
|
.
|
Ну, трейс же вам помог понять, что объект еще в памяти ). А вот как вы, не имея ссылок на удаленный объект, вызвали в нем метод, для меня осталось загадкой.
Сравнивая дампы памяти "во время" и "после" существования объекта. Поможет профилировщик памяти. Добавлено через 8 минут Кстати, пока тикает таймер и в нем есть ссылки на обработчики... Объекты, которым принадлежат обработчики будут жить ) |
|
|||||
|
Регистрация: Jul 2009
Адрес: Донецк
Сообщений: 25
|
Цитата:
Добавлено через 4 минуты Цитата:
|
|
|||||
|
Когда-то давно, когда у меня были такие же проблемы, я написал для этого класс, который позволял бы считать количество отслеживаемых элементов в памяти, записывая их в Dictionary со слабыми ключами (weakKeys):
package com.doctorstal.data{ import flash.events.TimerEvent; import flash.utils.Dictionary; import flash.utils.Timer; public class MemChecker{ private static var _dArr=new Array(); private static var _timer:Timer; private static var _inited:Boolean=false; private static function init(){ if(!_inited){ _inited=true; _timer=new Timer(2000); _timer.addEventListener(TimerEvent.TIMER,timerTickHandler); _timer.start(); } } public static function addItem(obj:Object,key:String="undef"){ init(); var _d:Dictionary; if(!(_dArr[key] is Dictionary)){ _d=new Dictionary(true); _dArr[key]=_d; }else{ _d=_dArr[key]; } _d[obj]={}; } public static function getItemCount(key:String):uint{ var _d=_dArr[key]; if(!(_d is Dictionary)) return 0; var obj:Object; var count=0; for(obj in _d){ count++; } return count; } private static function timerTickHandler(e:TimerEvent){ for(var i in _dArr){ trace("MemChecker: \""+i+"\":"+getItemCount(i)+" items."); } } } } и каждые 2 секунды выводился трейс с количеством неудаленных из памяти объектов, которые регистрировались. Можно, конечно, и весь список вывести, но зачем? |
|
|||||
|
Регистрация: Jul 2009
Адрес: Донецк
Сообщений: 25
|
Спасибо за помощь. Продвинулся немного. Обьект уже получается удалить. Оказывается если поставить листенер c weakReference=true, и оставить ссылку на обьект, то при проходе GC этот листенер слетает, а обьект остаётся нетронутым. Если же делать weakReference=false, то листенер не даст удалить обьект, даже если на него нет других ссылок.
Но оказывается в Flash Develop-e есть неплохой встроеный профайлер, который показывает все переменные и занимаемую ими память. Теперь я столкнулся теперь с другой проблемой. В каждом обьекте у меня есть еще обьект b2body из box2d библиотеки. Так вот удаляю этот обьект как по инструкции worldLink.DestroyBody(bodyLink); проверяю worldLink.GetBodyCount() - количество уменьшилось на один. В то же время профайлер показывает, что обьект остался в памяти даже после прохода GC. Пересматривал много раз, вроде ссылок на него больше нет, поэтому должен удалиться.. И опять у меня ступор. =/ |
|
|||||
|
Banned
[+1 05.11.11]
[+1 09.08.11] Регистрация: Jan 2010
Адрес: РФ. Кемеровская область
Сообщений: 3,243
|
Цитата:
Цитата:
А тела бокс2д жрут мало памяти, соответственно и рассматриваются GC позже более "ресурсоемких" объектов |
![]() |
![]() |
Часовой пояс GMT +4, время: 21:51. |
|
|
« Предыдущая тема | Следующая тема » |
| Теги |
| gc , обьект , удаление |
|
|