← Назад к вопросам

С какими проблемами производительности вы сталкивались и как их решали?

1.2 Junior🔥 131 комментариев
#Оптимизация

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Проблемы производительности в Unity: опыт и решения

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

1. Проблемы с рендерингом и вызовы Draw Calls

Проблема: Одна из самых частых проблем — чрезмерное количество Draw Calls, ведущее к низкому FPS на мобильных устройствах и слабом ПК. Сцена с сотнями динамических объектов с уникальными материалами легко превышает бюджет в 100-200 вызовов.

Решение:

  • Статический и динамический батчинг Unity через настройку Static Batching (для неподвижных объектов) и Dynamic Batching (для мелких мешей с одним материалом).
  • Ручной батчинг через GPU Instancing для одинаковых объектов (например, трава, деревья, пули). Это сокращает вызовы с N до 1-2 на тип объекта.
public class InstancedRenderer : MonoBehaviour
{
    public Mesh mesh;
    public Material material;
    public int instanceCount = 1000;
    private Matrix4x4[] matrices;

    void Start() {
        matrices = new Matrix4x4[instanceCount];
        // Заполняем матрицы трансформации для каждого экземпляра
        for (int i = 0; i < instanceCount; i++) {
            Vector3 position = new Vector3(Random.Range(-50, 50), 0, Random.Range(-50, 50));
            matrices[i] = Matrix4x4.TRS(position, Quaternion.identity, Vector3.one);
        }
    }

    void Update() {
        // Один вызов на отрисовку всех инстансов
        Graphics.DrawMeshInstanced(mesh, 0, material, matrices, instanceCount);
    }
}
  • Атласирование текстур (Texture Atlasing) для UI и 2D-спрайтов, чтобы разные объекты использовали один материал и лист текстур.
  • Оптимизация материалов: Уменьшение количества материалов на объекте, использование Shared Materials, отказ от ненужных свойств в шейдерах (например, параллакс на мобильных).

2. Проблемы с CPU: управление объектами и логикой

Проблема: Нагрузка на процессор из-за частого создания/уничтожения объектов (Instantiate/Destroy), неоптимизированных Update() методов и "тяжелых" алгоритмов поиска (например, FindGameObjectsWithTag, GetComponent в цикле).

Решение:

  • Пулы объектов (Object Pooling) для часто переиспользуемых префабов (пули, враги, эффекты). Это избавляет от дорогостоящих операций Instantiate и сборки мусора (Garbage Collection).
public class ObjectPool : MonoBehaviour
{
    public GameObject prefab;
    public int initialSize = 10;
    private Queue<GameObject> pool = new Queue<GameObject>();

    void Start() {
        for (int i = 0; i < initialSize; i++) {
            CreateNewObject();
        }
    }

    private GameObject CreateNewObject() {
        var obj = Instantiate(prefab);
        obj.SetActive(false);
        pool.Enqueue(obj);
        return obj;
    }

    public GameObject GetObject() {
        if (pool.Count == 0) CreateNewObject();
        var obj = pool.Dequeue();
        obj.SetActive(true);
        return obj;
    }

    public void ReturnObject(GameObject obj) {
        obj.SetActive(false);
        pool.Enqueue(obj);
    }
}
  • Оптимизация Update-методов: Замена Update на кешированные ссылки, использование Coroutines или InvokeRepeating для нечастых действий, применение событий вместо постоянной проверки условий.
  • Отказ от "тяжелых" методов в каждом кадре. Вызовы Find, GetComponent кешируются в Start() или Awake().
  • Профилирование через CPU Profiler для поиска "узких мест" в пользовательском коде.

3. Проблемы с памятью и сборкой мусора (Garbage Collection)

Проблема: Приложения испытывали "просадки" (фризы) каждые несколько секунд из-за частого запуска Garbage Collector (GC). Основные источники мусора: строковые операции, боксинг (boxing) типов значений, LINQ-запросы в реальном времени, выделение памяти в Update() (например, создание новых Vector3, List, массивов).

Решение:

  • Переиспользование коллекций: Использование List.Clear() или перезапись массива вместо создания нового.
  • Кеширование ссылок и объектов: Предварительное создание необходимых структур данных.
  • Отказ от LINQ в игровом цикле в пользу стандартных циклов for.
  • Использование StringBuilder для сложной конкатенации строк.
  • Профилирование через Memory Profiler для отслеживания аллокаций и утечек памяти (например, незаотписанные подписчики событий).

4. Проблемы оптимизации физики (Unity Physics)

Проблема: Сложные сцены с множеством коллайдеров, особенно MeshCollider, или с большим количеством Rigidbody-объектов, взаимодействующих друг с другом, приводили к падению производительности.

Решение:

  • Замена MeshCollider на примитивы (BoxCollider, SphereCollider) или их композицию для статической геометрии.
  • Применение Layer-Based Collision Detection и настройка матрицы столкновений, чтобы отключать ненужные проверки.
  • Для неподвижных объектов — установка Rigidbody.isKinematic = true или отметка статических объектов как Static в инспекторе.
  • Использование упрощенных коллайдеров для далеких или второстепенных объектов.

5. Проблемы с загрузкой ассетов и управлением сценами

Проблема: Долгие загрузки уровня, "фризы" при появлении новых объектов или подгрузке контента "на лету".

Решение:

  • Асинхронная загрузка сцен через SceneManager.LoadSceneAsync.
  • Addressables Asset System или AssetBundles для контролируемой потоковой загрузки и выгрузки ресурсов, избегая единого огромного билда.
  • Предзагрузка (preloading) критичных объектов в пулы на этапе загрузки или в фоновом режиме.
  • Прогрессивное увеличение детализации (LOD) не только для рендера, но и для логики.

Общий рабочий процесс при решении любой проблемы производительности всегда начинается с Profiler Window (CPU, GPU, Memory, Physics). Без данных профилирования оптимизация — это "стрельба по площадям". Я определяю "бутылочное горлышко" (CPU-bound, GPU-bound, memory-bound), затем использую соответствующие инструменты (Frame Debugger для рендеринга) и применяю целенаправленные техники оптимизации, постоянно проверяя результат. Приоритет всегда отдается решениям, дающим наибольший прирост при минимальном усложнении кода.

С какими проблемами производительности вы сталкивались и как их решали? | PrepBro