>
>
>
V4003. Unity Engine. Avoid capturing va…


V4003. Unity Engine. Avoid capturing variable in performance-sensitive context. This can lead to decreased performance.

Анализатор обнаружил захват переменной в лямбда-выражении внутри часто выполняемого метода. Захват переменных может приводить к снижению производительности из-за дополнительного выделения памяти.

Рассмотрим пример:

void Update()
{
  ....
  List<int> numbers = GetNumbers();
  int divisor = GetDivisor();
  var result = numbers.Select(x => x / divisor);
  ....
}

Здесь 'Update' — метод Unity, выполняющий покадровое обновление. Метод 'Update' — часто вызываемый, и его не рекомендуется нагружать лишними операциями.

В приведенном примере используется лямбда-выражение с захватом переменной 'divisor'. Как упоминалось ранее, захват переменной из внешнего контекста приводит к дополнительному созданию объекта.

Таким образом, представленный участок кода создает дополнительную нагрузку на GC.

Оптимальная реализация метода может выглядеть следующим образом:

void Update()
{
  ....
  List<int> numbers = GetNumbers();
  int divisor = GetDivisor();

  var result = new List<int>(numbers.Count);
  for (int i = 0; i < numbers.Count; i++)
  {
    result.Add(numbers[i]/divisor);
  }
  ....
}

Использование собственной реализации, аналогичной 'Select', позволяет избавиться от дополнительного выделения памяти и тем самым снизить нагрузку на GC.

Рассмотрим еще один пример:

void Update()
{
  ....
  List<int> numbers = GetNumbers();
  int divisor = GetDivisor();

  if (AreAllMultipleOf(numbers, divisor))
    ....
}

bool AreAllMultipleOf(List<int> lst, int divisor)
{
  return lst.All(elem => elem % divisor == 0);
}

Здесь из метода 'Update' вызывается метод 'AreAllMultipleOf', который определяет, являются ли все полученные числа кратными значению 'divisor'. Так же, как и ранее: 'Update' — часто вызываемый метод, выполняющий покадровое обновление в Unity.

В представленном случае метод 'AreAllMultipleOf' регулярно выполняется внутри 'Update', а значит, также является часто вызываемым.

Метод 'AreAllMultipleOf' для выполнения проверки использует лямбда-выражение с захватом переменных. Это приводит к дополнительному выделению памяти, которое может негативно сказаться на производительности приложения.

Оптимальная реализация может выглядеть следующим образом:

void Update()
{
  ....
  List<int> numbers = GetNumbers();
  int divisor = GetDivisor();

  if (AreAllMultipleOf(numbers, divisor)) 
    ....
}

bool AreAllMultipleOf(List<int> lst, int divisor)
{
  foreach (int num in lst)
  {
    if (num % divisor != 0)
      return false;
  }
  return true;
}

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