diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp index 07038f146..160e07a91 100644 --- a/Source/Engine/Engine/Engine.cpp +++ b/Source/Engine/Engine/Engine.cpp @@ -20,6 +20,7 @@ #include "Engine/Threading/MainThreadTask.h" #include "Engine/Threading/ThreadRegistry.h" #include "Engine/Graphics/GPUDevice.h" +#include "Engine/Scripting/ManagedCLR/MCore.h" #include "Engine/Scripting/ScriptingType.h" #include "Engine/Content/Content.h" #include "Engine/Content/JsonAsset.h" @@ -309,6 +310,14 @@ void Engine::OnUpdate() // Update services EngineService::OnUpdate(); + +#ifdef USE_NETCORE + // Force GC to run in background periodically to avoid large blocking collections causing hitches + if (Time::Update.TicksCount % 60 == 0) + { + MCore::GC::Collect(MCore::GC::MaxGeneration(), MGCCollectionMode::Forced, false, false); + } +#endif } void Engine::OnLateUpdate() diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index 7e2755603..ca94bed04 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -1041,6 +1041,24 @@ namespace FlaxEngine.Interop valueHandle.Free(); } + [UnmanagedCallersOnly] + internal static void GCCollect(int generation, int mode, bool blocking, bool compacting) + { + GC.Collect(generation, (GCCollectionMode)mode, blocking, compacting); + } + + [UnmanagedCallersOnly] + internal static int GCMaxGeneration() + { + return GC.MaxGeneration; + } + + [UnmanagedCallersOnly] + internal static void GCWaitForPendingFinalizers() + { + GC.WaitForPendingFinalizers(); + } + [UnmanagedCallersOnly] internal static ManagedHandle GetTypeClass(ManagedHandle typeHandle) { diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.h b/Source/Engine/Scripting/ManagedCLR/MCore.h index 497c27657..6bc430f0e 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.h +++ b/Source/Engine/Scripting/ManagedCLR/MCore.h @@ -106,6 +106,8 @@ public: { static void Collect(); static void Collect(int32 generation); + static void Collect(int32 generation, MGCCollectionMode collectionMode, bool blocking, bool compacting); + static int32 MaxGeneration(); static void WaitForPendingFinalizers(); static void WriteRef(void* ptr, MObject* ref); static void WriteValue(void* dst, void* src, int32 count, const MClass* klass); diff --git a/Source/Engine/Scripting/ManagedCLR/MTypes.h b/Source/Engine/Scripting/ManagedCLR/MTypes.h index 1ba69fce1..f0ab08b96 100644 --- a/Source/Engine/Scripting/ManagedCLR/MTypes.h +++ b/Source/Engine/Scripting/ManagedCLR/MTypes.h @@ -56,6 +56,14 @@ enum class MTypes : uint32 Enum = 0x55, }; +enum class MGCCollectionMode +{ + Default = 0, + Forced = 1, + Optimized = 2, + Aggressive = 3 +}; + #if USE_NETCORE enum class MTypeAttributes : uint32; diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 07d9ea92a..c2e02a533 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -422,19 +422,36 @@ void MCore::GCHandle::Free(const MGCHandle& handle) void MCore::GC::Collect() { PROFILE_CPU(); - // TODO: call System.GC.Collect() + static void* GCCollectPtr = GetStaticMethodPointer(TEXT("GCCollect")); + CallStaticMethod(GCCollectPtr, MaxGeneration(), (int)MGCCollectionMode::Default, true, false); } void MCore::GC::Collect(int32 generation) { PROFILE_CPU(); - // TODO: call System.GC.Collect(int32) + static void* GCCollectPtr = GetStaticMethodPointer(TEXT("GCCollect")); + CallStaticMethod(GCCollectPtr, generation, (int)MGCCollectionMode::Default, true, false); +} + +void MCore::GC::Collect(int32 generation, MGCCollectionMode collectionMode, bool blocking, bool compacting) +{ + PROFILE_CPU(); + static void* GCCollectPtr = GetStaticMethodPointer(TEXT("GCCollect")); + CallStaticMethod(GCCollectPtr, generation, (int)collectionMode, blocking, compacting); +} + +int32 MCore::GC::MaxGeneration() +{ + static void* GCMaxGenerationPtr = GetStaticMethodPointer(TEXT("GCMaxGeneration")); + static int32 maxGeneration = CallStaticMethod(GCMaxGenerationPtr); + return maxGeneration; } void MCore::GC::WaitForPendingFinalizers() { PROFILE_CPU(); - // TODO: call System.GC.WaitForPendingFinalizers() + static void* GCWaitForPendingFinalizersPtr = GetStaticMethodPointer(TEXT("GCWaitForPendingFinalizers")); + CallStaticMethod(GCWaitForPendingFinalizersPtr); } void MCore::GC::WriteRef(void* ptr, MObject* ref) diff --git a/Source/Engine/Scripting/Runtime/Mono.cpp b/Source/Engine/Scripting/Runtime/Mono.cpp index 3ebb92ccc..05c01fd8a 100644 --- a/Source/Engine/Scripting/Runtime/Mono.cpp +++ b/Source/Engine/Scripting/Runtime/Mono.cpp @@ -828,6 +828,18 @@ void MCore::GC::Collect(int32 generation) mono_gc_collect(generation); } +void MCore::GC::Collect(int32 generation, MGCCollectionMode collectionMode, bool blocking, bool compacting) +{ + PROFILE_CPU(); + mono_gc_collect(generation); +} + +int32 MCore::GC::MaxGeneration() +{ + PROFILE_CPU(); + return mono_gc_max_generation(); +} + void MCore::GC::WaitForPendingFinalizers() { PROFILE_CPU(); diff --git a/Source/Engine/Scripting/Runtime/None.cpp b/Source/Engine/Scripting/Runtime/None.cpp index c9e51f8ea..9f47476ba 100644 --- a/Source/Engine/Scripting/Runtime/None.cpp +++ b/Source/Engine/Scripting/Runtime/None.cpp @@ -160,6 +160,15 @@ void MCore::GC::Collect(int32 generation) { } +void MCore::GC::Collect(int32 generation, MGCCollectionMode collectionMode, bool blocking, bool compacting) +{ +} + +int32 MCore::GC::MaxGeneration() +{ + return 0; +} + void MCore::GC::WaitForPendingFinalizers() { }