Работа с классами в Job System: Магия указателей и GC Handle
Взмахивает лапой
Предисловие
В предыдущем посте мы рассмотрели работу со структурами в Job System. Сегодня мы пойдём дальше и покажем, как можно использовать классы в Jobs, обходя стандартные ограничения Unity.
Суть метода
Основная идея заключается в использовании GCHandle для получения стабильного указателя на управляемый объект:
// В основном потоке
var handle = GCHandle.Alloc(testClass, GCHandleType.Pinned);
classPtr = (IntPtr)handle;
// В Job'е
GCHandle handle = GCHandle.FromIntPtr(classPtr);
TestClassForJob obj = (TestClassForJob)handle.Target;
Преимущества подхода:
Нет необходимости копировать данные между потоками
Сохраняется вся функциональность классов (наследование, полиморфизм)
Чистый и понятный код
Прямой доступ к данным без маршалинга
Ограничения и особенности
Burst компиляция:
В редакторе (Mono) работает без проблем
В билде с IL2CPP может потребоваться отключение Burst для таких jobs
Теряем производительность Burst, но выигрываем в удобстве разработки
Безопасность:
Объект "закреплён" в памяти (pinned)
GC не может его перемещать
Важно правильно освобождать GCHandle
IL2CPP специфика:
IL2CPP совместим с данным подходом
Производительность может отличаться от Mono
Требуется дополнительное тестирование в Development Build
Пример использования
public class TestJobClass : MonoBehaviour
{
[SerializeField] private TestClassForJob testClass;
private IntPtr classPtr;
private JobHandle jobHandle;
void Start()
{
// Закрепляем объект в памяти
var handle = GCHandle.Alloc(testClass, GCHandleType.Pinned);
classPtr = (IntPtr)handle;
var job = new ManagedTestJob { classPtr = classPtr };
jobHandle = job.Schedule();
}
void OnDestroy()
{
jobHandle.Complete();
// Важно освободить handle!
if (classPtr != IntPtr.Zero)
{
GCHandle.FromIntPtr(classPtr).Free();
}
}
}
Производительность
Несмотря на отсутствие Burst компиляции, этот метод всё равно даёт преимущества:
Нет overhead на копирование данных
Меньше нагрузка на сборщик мусора
Прямой доступ к данным быстрее, чем маршалинг
Заключение
Этот эксперимент, как и предыдущий со структурами, показал отличные результаты! Мы получили рабочий способ использования классов в Job System, который особенно полезен когда:
Важнее удобство разработки, чем максимальная производительность
Требуется сохранить возможности ООП
Нужно избежать копирования больших объёмов данных
Гордо виляет хвостом
⚠️ Важно помнить:
Всегда освобождайте GCHandle
Тестируйте в реальных условиях (IL2CPP build)
Следите за правильным закрытием jobs перед освобождением handle
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization #MultiThreading #UnsafeCode #UnityJobs #BurstCompiler #Programming