V4008. Unity Engine. Avoid using memory allocation Physics APIs in performance-sensitive context.
Анализатор обнаружил в часто выполняемом коде использование аллоцирующих память методов Physics.RaycastAll
, Physics2D.OverlapSphere
или подобных им.
Такие методы создают массив при каждом вызове, что может снизить производительность. Вместо них стоит использовать неаллоцирующие вариации методов, в которые можно передать предварительно выделенный массив.
Рассмотрим пример:
public class HitScript : MonoBehaviour
{
void Update()
{
AllocMethod();
}
void AllocMethod()
{
RaycastHit[] hitsTargets = Physics.RaycastAll(transform.position,
transform.forward);
foreach (RaycastHit hit in hitsTargets)
{
if (hit.collider.gameObject.name != "PlayerAdvanced")
{
....
}
}
}
}
Update
будет каждый кадр вызывать AllocMethod
, использующий аллоцирующий метод RaycastAll
. Из-за постоянного создания новых массивов, которые содержат попадания луча, производительность ухудшится.
Данный код можно оптимизировать. Для этого нужно заменить метод RaycastAll
на неаллоцирующий метод RaycastNonAlloc
и использовать его вместе с предварительно выделенным массивом.
Вариант оптимальной реализации:
public class HitScript : MonoBehaviour
{
void Update()
{
NonAllocMethod();
}
const int MAX_RAYCAST_HIT_COUNT = 10;
RaycastHit[] _hitsTargets = new RaycastHit[MAX_RAYCAST_HIT_COUNT];
void NonAllocMethod()
{
int countOfResults = Physics.RaycastNonAlloc(new Ray(transform.position,
transform.forward ),
_hitsTargets);
for(int i = 0; i < countOfResults; i++)
{
if (_hitsTargets[i].collider.gameObject.name != "PlayerAdvanced")
{
....
}
}
}
}
Для использования RaycastNonAlloc
заранее создан вспомогательный массив _hitsTargets
. Максимальное количество попаданий луча ограничено размером этого массива. После вызова метода RaycastNonAlloc
количество попаданий луча будет записано в переменную countOfResults
, а сами попадания будут записаны в массив _hitsTargets
. Таким образом, в каждом кадре будет использоваться массив _hitsTargets
, под который память выделяется лишь один раз.
На момент написания документации к диагностике в классе Physics2D
все методы с припиской "NonAlloc" помечены как устаревшие, им на замену можно использовать неаллоцирующие перегрузки обычных методов. Например, вместо Physics2D.BoxCastAll
стоит использовать перегрузку Physics2D.BoxCast
, принимающую массив для получения всех попаданий.