Фризы из-за GC.Collect в Unity3D (C#)
От: azazeo Беларусь http://about.me/azazeo
Дата: 17.03.12 19:29
Оценка:
Игра есть на движке Unity3D. FPS в целом ровный, мощности машины хватает, графика не тормозит. Но местами регулярно выскакивают фризы, в профайлере видны резкие пики-скачки GC.Collect().
Из-за определённых особенностей вполне уверен, что этот GC можно отключить — если да, то как? А если нет, то что в скриптах принципиально поправить?
Искал на суппорте и формах Юнити3Д ответы — мало что нашёл (там какое-то всё нехардкорное, и в глубины никто не лезет). Подскажите пожалуйста.
Re: Фризы из-за GC.Collect в Unity3D (C#)
От: Nikolay_P_I  
Дата: 17.03.12 19:52
Оценка:
Здравствуйте, azazeo, Вы писали:

A>Игра есть на движке Unity3D. FPS в целом ровный, мощности машины хватает, графика не тормозит. Но местами регулярно выскакивают фризы, в профайлере видны резкие пики-скачки GC.Collect().

A>Из-за определённых особенностей вполне уверен, что этот GC можно отключить — если да, то как? А если нет, то что в скриптах принципиально поправить?
A>Искал на суппорте и формах Юнити3Д ответы — мало что нашёл (там какое-то всё нехардкорное, и в глубины никто не лезет). Подскажите пожалуйста.

Убедитесь сначала, что GC там вообще в отдельном потоке мусор собирает, а не в основном. Ссылку не дам — не помню.
Re: Фризы из-за GC.Collect в Unity3D (C#)
От: enCobalt  
Дата: 17.03.12 19:54
Оценка:
Здравствуйте, azazeo, Вы писали:

A>Игра есть на движке Unity3D. FPS в целом ровный, мощности машины хватает, графика не тормозит. Но местами регулярно выскакивают фризы, в профайлере видны резкие пики-скачки GC.Collect().

A>Из-за определённых особенностей вполне уверен, что этот GC можно отключить — если да, то как? А если нет, то что в скриптах принципиально поправить?
A>Искал на суппорте и формах Юнити3Д ответы — мало что нашёл (там какое-то всё нехардкорное, и в глубины никто не лезет). Подскажите пожалуйста.

Если GC решил делать глубокую очистку, значит на то у него были веские причины, это все что я могу сказать по существу.
b]если ты воткнулся в GC ты где-то сильно не прав[/b]!

GC не тупой автомат, он динамически ориентируется на имеющиеся ресурсы.

Ищи в архитектуре своего приложения. Не в коде, а именно в архитектуре. Например ты для каждой кнопки каждый раз делаешь New Brush, c точки зрения кода ты прав, но по архитектуре, если ты будешь всегда применять один аттрибут из ресурсов вместо нового браша каждый раз, то ты в 100500 раз уменьшишь нагрузку на GC, и т.д. Еще у новичков-программеров частая тема с эвентами — вы подписываетесь на эвент контрола, и забиваете что подписались. Сгорит ведь подписка, если окно с этим контролом убивается?
Если грубо — так и есть.

Если подробнее, то не совсем, контрол и его эвент в разных поколениях GC, контролы и его аттрибуты убиваются быстро, а вот эвенты от них копятся, в какой-то момент выходит коллапс и GC начинает глубокую очистку и там только сносит умерших подписчиков эвентов, которые сами не отписались. Всегда при возможности сами указывайте что отписываетесь от эвента.
Хочу инвайт на хабру :)
Re[2]: Фризы из-за GC.Collect в Unity3D (C#)
От: azazeo Беларусь http://about.me/azazeo
Дата: 17.03.12 20:24
Оценка:
Здравствуйте, Nikolay_P_I, Вы писали:

N_P>Здравствуйте, azazeo, Вы писали:


A>>Игра есть на движке Unity3D. FPS в целом ровный, мощности машины хватает, графика не тормозит. Но местами регулярно выскакивают фризы, в профайлере видны резкие пики-скачки GC.Collect().

A>>Из-за определённых особенностей вполне уверен, что этот GC можно отключить — если да, то как? А если нет, то что в скриптах принципиально поправить?
A>>Искал на суппорте и формах Юнити3Д ответы — мало что нашёл (там какое-то всё нехардкорное, и в глубины никто не лезет). Подскажите пожалуйста.

N_P>Убедитесь сначала, что GC там вообще в отдельном потоке мусор собирает, а не в основном. Ссылку не дам — не помню.


Поясню, что в Юнити у игровых объектов есть набор методов (но, как говорят немногие знающие — это не совсем методы объектов как таковые, а сообщения, однако не суть): Awake (инициализация), Start (после инициализации), Update (каждый фрэйм), FixedUpdate (почти как Update, только через постоянные интервалы — для физики и всего, что должно проверяться постоянно, но не слишком часто). По сути больше особо ничего не дёргается мною.

Может ли быть проблема из-за запуска Coroutine (yieldы) и Invoke() для выстраивания последовательностей анимаций?
Я понимаю, что делать в FixedUpdate() что-то вроде

for (int i = 0; i++, i < n)
{
    GameObject _obj = new GameObject(...бла-бла-бла...
}


это очень плохо и такого избегаю
unity3d c#
Re: Фризы из-за GC.Collect в Unity3D (C#)
От: Мишень-сан  
Дата: 19.03.12 08:59
Оценка:
Здравствуйте, azazeo, Вы писали:

A>Игра есть на движке Unity3D. FPS в целом ровный, мощности машины хватает, графика не тормозит. Но местами регулярно выскакивают фризы, в профайлере видны резкие пики-скачки GC.Collect().

A>Из-за определённых особенностей вполне уверен, что этот GC можно отключить — если да, то как? А если нет, то что в скриптах принципиально поправить?
A>Искал на суппорте и формах Юнити3Д ответы — мало что нашёл (там какое-то всё нехардкорное, и в глубины никто не лезет). Подскажите пожалуйста.

Учтите, что Unity3d работает не на .NET, а на Mono. GC у них работают по разному. От этого и отталкивайтесь.
Re: Фризы из-за GC.Collect в Unity3D (C#)
От: alexzz  
Дата: 19.03.12 15:48
Оценка:
Здравствуйте, azazeo, Вы писали:

A>Игра есть на движке Unity3D. FPS в целом ровный, мощности машины хватает, графика не тормозит. Но местами регулярно выскакивают фризы, в профайлере видны резкие пики-скачки GC.Collect().

A>Из-за определённых особенностей вполне уверен, что этот GC можно отключить — если да, то как? А если нет, то что в скриптах принципиально поправить?

Не знаю, можно ли GC отключить, но если можно, это приведёт к тому, что твоя программа рано или поздно упадёт из-за нехватки памяти. Посмотри, как с каждым кадром меняется GC.GetTotalMemory(), даже когда ты ничего не делаешь.

Я знаю только один способ успокоить сборщик мусора: не пичкать его таким количеством данных, которое он не может обработать за приемлемое время. У сборки мусора есть две характеристики: частота и длительность.

1. Частота:
Сборка мусора запускается тогда, когда сборщик видит, что свободной памяти стало мало.

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

Ещё памяти может быть мало из-за того, что её много тратится на временные сиюминутные нужды. Можно уменьшить размер временных структур данных и/или создать один или несколько экземпляром таких структур и использовать их повторно, каждый раз не пересоздавая.

2. Длительность:

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

Соответственно, чем больше в куче живых объектов, тем дольше сборщику в ней копаться. Стоит подумать, на самом ли деле нужно держать все эти объекты живыми. Ещё стоит, по-возможности, использовать value-типы вместо ссылочных и всегда generic-коллекции вместо ArrayList, Hashtable и прочего дерьма мамонта, как любят многие программисты под Unity3D.

A>Искал на суппорте и формах Юнити3Д ответы — мало что нашёл (там какое-то всё нехардкорное, и в глубины никто не лезет).


На официальном форуме или на UnityAnswers намного больше шансов получить толковый ответ на любой вопрос, чем на всех наших ресурсах по Unity, вместе взятых. Там проблема в том, что активность пользователей на порядок, если не два, выше, чем у нас, и если нужный человек не увидел твой вопрос сразу, то вероятно больше и не увидит.
Re[3]: Фризы из-за GC.Collect в Unity3D (C#)
От: alexzz  
Дата: 19.03.12 15:48
Оценка:
Здравствуйте, azazeo, Вы писали:

A>Поясню, что в Юнити у игровых объектов есть набор методов (но, как говорят немногие знающие — это не совсем методы объектов как таковые, а сообщения, однако не суть): Awake (инициализация), Start (после инициализации), Update (каждый фрэйм), FixedUpdate (почти как Update, только через постоянные интервалы — для физики и всего, что должно проверяться постоянно, но не слишком часто). По сути больше особо ничего не дёргается мною.


Единственная необычность этих методов в том, что если Unity3D с помощью рефлексии обнаруживает у наследников класса MonoBehaivour методы с такими названиями, то автоматически вызывает их в соответствующие моменты времени. В остальном это самые обыкновенные методы. Где-то я натыкался на сообщение от разработчиков, что они может и хотели бы сейчас использовать виртуальные вызовы вместо рефлексии, но теперь уже поздно что-то менять.
Re: Фризы из-за GC.Collect в Unity3D (C#)
От: syrompe  
Дата: 19.03.12 16:11
Оценка:
Здравствуйте, azazeo, Вы писали:

A>Игра есть на движке Unity3D. FPS в целом ровный, мощности машины хватает, графика не тормозит. Но местами регулярно выскакивают фризы, в профайлере видны резкие пики-скачки GC.Collect().

A>Из-за определённых особенностей вполне уверен, что этот GC можно отключить — если да, то как? А если нет, то что в скриптах принципиально поправить?
A>Искал на суппорте и формах Юнити3Д ответы — мало что нашёл (там какое-то всё нехардкорное, и в глубины никто не лезет). Подскажите пожалуйста.

Аналогичная проблема была, когда писали игрушку под Windows Phone.
Ну собственно вам уже отписали выше.
Надо стараться чтобы GC после загрузки очередного уровня не вызывался вообще.
Т.е. не генерируем мусор. Но у нас в руках был профайлер — не знаю есть ли для Mono.
Для начала поищите оператор вызовы 'new' и постарайтесь лишнего не создавать.
Там, объект уж очень нужен можно использовать "пул".
Потом проверьте не "боксится" ли что-нибудь лишнего (Dictitionary.TryGetValue для value типа приводил к боксингу)
Чаще всего при вызове евента: handler(this, new EventArgs()).
В релизной сборке, кстати, много чего оптимизируется и GC дергается меньше.

Но это все про MS .Net — как оно в Mono не знаю.
Re: Фризы из-за GC.Collect в Unity3D (C#)
От: azazeo Беларусь http://about.me/azazeo
Дата: 19.03.12 22:07
Оценка:
Всем спасибо за советы, перелопатил почти весь код, теперь работа GC почти незаметна, да и в целом фпс поднялся процентов на 20-30. Но осталась (а точнее проявилась на фоне общего процветания) одна беда — в нескольких моментах — а игра у меня типа аттракциона, с заранее жестко заанимированной камерой, никакой свободы действий и прочего управления событиями со стороны игрока, — так вот в нескольких моментах (и всегда одних и тех же) происходит жуткий фриз, а профайлер пишет, что это некий Device.Present съедает все ресурсы. Краткий гуглинг показал странное — мол этот device.present — это всего лишь ожидание игрой, как будто у нас слишком большой фпс при включеной вертикальной синхронизации. Но не пол-секунды же ожидать! При этом такое поведение только в билде — если запускать проект из-под редактора — всё отлично!
Ладно, с этими вопросами я уже сходил и на оф. форум, и в саппорт, буду ждать что там скажут, да и и сам копать продолжу.
Re[2]: Фризы из-за GC.Collect в Unity3D (C#)
От: azazeo Беларусь http://about.me/azazeo
Дата: 19.03.12 22:15
Оценка:
Здравствуйте, alexzz, Вы писали:

A>Соответственно, чем больше в куче живых объектов, тем дольше сборщику в ней копаться. Стоит подумать, на самом ли деле нужно держать все эти объекты живыми. Ещё стоит, по-возможности, использовать value-типы вместо ссылочных и всегда generic-коллекции вместо ArrayList, Hashtable и прочего дерьма мамонта, как любят многие программисты под Unity3D.


Из таких вещей я использую только T[] и List<T>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.