Указатели функций C# вызывают нарушение прав доступа при вызове из C++

В следующем фрагменте кода я использую указатели на функции C#, чтобы не использовать тип делегата для повышения производительности. Код работает нормально, когда я использую тип делегата, маршалируемый как указатель на функцию, никаких исключений и никаких проблем. Однако при изменении его с делегата на указатель на функцию иногда возникает нарушение прав доступа.

Код изменен для удаления пространств имен и префиксов, не имеющих отношения к вопросу.

public static class Engine
{
    // Causing issues with sometimes throwing access violation
    [DllImport("engine", CallingConvention = CallingConvention.Cdecl)]
    public static unsafe extern UInt32 EventScheduler_ScheduleLocalEvent(
        int priority, UInt64 delay, delegate* unmanaged[Cdecl]<nint, void> callback, nint obj);

    // Works fine every time, but is much slower seems due to delegate instatiations
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void EventScheduler_ScheduleLocalEvent_callbackDelegate(nint obj);
    [DllImport("engine", CallingConvention = CallingConvention.Cdecl)]
    public static unsafe extern UInt32 EventScheduler_ScheduleLocalEvent(
        int priority,
        UInt64 delay,
        [MarshalAs(UnmanagedType.FunctionPtr)] EventScheduler_ScheduleLocalEvent_callbackDelegate callback,
        nint obj);

}

public static class EventScheduler
{
    public delegate void EventCallback();

    // attribute is only present in the function pointer senario
    [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl ) }, EntryPoint = "ScheduleLocalEvent_EventCallbackFunction")]
    private static void ScheduleLocalEvent_EventCallbackFunction(nint handlePtr)
    {
        Thread.BeginThreadAffinity();
        GCHandle handle = GCHandle.FromIntPtr(handlePtr);
        var cb          = (EventScheduler.EventCallback)handle.Target!;
        cb();
        handle.Free();
        Thread.EndThreadAffinity();
    }
    public static UInt32 ScheduleLocalEvent(int priority, SimulationTime delayTime, EventCallback eventCallback)
    {
        GCHandle handle  = GCHandle.Alloc(eventCallback, GCHandleType.Normal);
        IntPtr handlePtr = GCHandle.ToIntPtr(handle);
        unsafe
        {
            return Engine.EventScheduler_ScheduleLocalEvent(
                priority, delayTime, &ScheduleLocalEvent_EventCallbackFunction, handlePtr);
        }
    }

}

На стороне C++

#define API extern "C" __declspec(dllexport)

API uint32_t EventScheduler_ScheduleLocalEvent(int priority, uint64_t delay, void(__cdecl* callback)(void* obj), void* obj)
{
    ERSAssert(Ers::Core::InsideSubModel());
    Core::SyncManagerBase& syncManager = Ers::Core::GetSyncManagerBase();
    return syncManager.ScheduleEvent(priority, delay, [callback, obj]() { callback(obj); });
}

Следующий вывод выдается при запуске программы.

AWealthOfRows.exe (процесс 39016) завершился с кодом -1073741819.

Со следующим выводом

`' AWealthOfRows.exe' (Win32): Loaded
'C:\Projects\Testing\Enterprise_Resource_Simulator\bindings\CSharp\AWealthOfRows\bin\Debug\net8.0\AWealthOfRows.exe'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Windows\System32\ntdll.dll'. 
'AWealthOfRows.exe' (Win32): Loaded
'C:\Windows\System32\kernel32.dll'.  'AWealthOfRows.exe' (Win32):
Loaded 'C:\Windows\System32\KernelBase.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Windows\System32\user32.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Windows\System32\win32u.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Windows\System32\gdi32.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Windows\System32\gdi32full.dll'. 
'AWealthOfRows.exe' (Win32): Loaded
'C:\Windows\System32\msvcp_win.dll'.  'AWealthOfRows.exe' (Win32):
Loaded 'C:\Windows\System32\ucrtbase.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Windows\System32\shell32.dll'. 
'AWealthOfRows.exe' (Win32): Loaded
'C:\Windows\System32\advapi32.dll'.  'AWealthOfRows.exe' (Win32):
Loaded 'C:\Windows\System32\msvcrt.dll'.  'AWealthOfRows.exe' (Win32):
Loaded 'C:\Windows\System32\sechost.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Windows\System32\bcrypt.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Windows\System32\rpcrt4.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Windows\System32\imm32.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Program
Files\dotnet\host\fxr\9.0.0-preview.3.24172.9\hostfxr.dll'. 
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\hostpolicy.dll'. 
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\coreclr.dll'. 
'AWealthOfRows.exe' (Win32): Loaded 'C:\Windows\System32\ole32.dll'. 
'AWealthOfRows.exe' (Win32): Loaded 'C:\Windows\System32\combase.dll'.
'AWealthOfRows.exe' (Win32): Loaded
'C:\Windows\System32\oleaut32.dll'.  'AWealthOfRows.exe' (Win32):
Loaded 'C:\Windows\System32\bcryptprimitives.dll'.  The thread 41728
has exited with code 0 (0x0). 'AWealthOfRows.exe' (Win32): Loaded
'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Private.CoreLib.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\clrjit.dll'. 
'AWealthOfRows.exe' (CoreCLR: DefaultDomain): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Private.CoreLib.dll'.
'AWealthOfRows.exe' (Win32): Loaded
'C:\Windows\System32\kernel.appcore.dll'.  'AWealthOfRows.exe'
(Win32): Loaded
'C:\Projects\Testing\Enterprise_Resource_Simulator\bindings\CSharp\AWealthOfRows\bin\Debug\net8.0\AWealthOfRows.dll'.
The thread 41464 has exited with code 0 (0x0). 'AWealthOfRows.exe'
(CoreCLR: clrhost): Loaded
'C:\Projects\Testing\Enterprise_Resource_Simulator\bindings\CSharp\AWealthOfRows\bin\Debug\net8.0\AWealthOfRows.dll'.
Symbols loaded. 'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Runtime.dll'. 
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Runtime.dll'. 
'AWealthOfRows.exe' (Win32): Loaded 'C:\Windows\System32\icu.dll'. 
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program Files\Microsoft Visual
Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\HotReload\Microsoft.Extensions.DotNetDeltaApplier.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'c:\program
files\microsoft visual
studio\2022\community\common7\ide\commonextensions\microsoft\hotreload\Microsoft.Extensions.DotNetDeltaApplier.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.IO.Pipes.dll'. 
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.IO.Pipes.dll'. 
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Linq.dll'. 
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Linq.dll'. 
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Collections.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Collections.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Console.dll'. 
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Console.dll'. 
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Threading.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Threading.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Runtime.InteropServices.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Runtime.InteropServices.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Threading.Overlapped.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Threading.Overlapped.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Security.AccessControl.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Security.AccessControl.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Security.Principal.Windows.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Security.Principal.Windows.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Windows\System32\ntmarta.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Security.Claims.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Security.Claims.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Runtime.Loader.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Runtime.Loader.dll'.
'AWealthOfRows.exe' (Win32): Loaded
'C:\Projects\Testing\Enterprise_Resource_Simulator\bindings\CSharp\AWealthOfRows\bin\Debug\net8.0\Ers.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Collections.Concurrent.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded
'C:\Projects\Testing\Enterprise_Resource_Simulator\bindings\CSharp\AWealthOfRows\bin\Debug\net8.0\Ers.dll'.
Symbols loaded. 'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded
'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Collections.Concurrent.dll'.
'AWealthOfRows.exe' (Win32): Loaded
'C:\Projects\Testing\Enterprise_Resource_Simulator\bindings\CSharp\AWealthOfRows\bin\Debug\net8.0\ers-engine.dll'.
Symbols loaded. 'AWealthOfRows.exe' (Win32): Loaded
'C:\Windows\System32\setupapi.dll'.  'AWealthOfRows.exe' (Win32):
Loaded 'C:\Windows\System32\winmm.dll'.  'AWealthOfRows.exe' (Win32):
Loaded 'C:\Windows\System32\version.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Windows\System32\vcruntime140d.dll'. 
'AWealthOfRows.exe' (Win32): Loaded
'C:\Windows\System32\msvcp140d.dll'.  'AWealthOfRows.exe' (Win32):
Loaded 'C:\Windows\System32\vcruntime140_1d.dll'.  'AWealthOfRows.exe'
(Win32): Loaded 'C:\Windows\System32\ucrtbased.dll'. 
'AWealthOfRows.exe' (Win32): Loaded
'C:\Windows\System32\cfgmgr32.dll'.  'AWealthOfRows.exe' (Win32):
Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Diagnostics.Process.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Diagnostics.Process.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.ComponentModel.Primitives.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.ComponentModel.Primitives.dll'.
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Memory.dll'. 
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Memory.dll'. 
'AWealthOfRows.exe' (Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Text.Encoding.Extensions.dll'.
The thread 20540 has exited with code 0 (0x0). The thread 23312 has
exited with code 0 (0x0). 'AWealthOfRows.exe' (CoreCLR: clrhost):
Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Text.Encoding.Extensions.dll'.
The thread 9224 has exited with code 0 (0x0). 'AWealthOfRows.exe'
(Win32): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Threading.Thread.dll'.
'AWealthOfRows.exe' (CoreCLR: clrhost): Loaded 'C:\Program
Files\dotnet\shared\Microsoft.NETCore.App\8.0.5\System.Threading.Thread.dll'.
Exception thrown at 0x000001F303570860 in AWealthOfRows.exe:
0xC0000005: Access violation reading location 0x000001F30385FB32. The
Common Language Runtime cannot stop at this exception. Common causes
include: incorrect COM interop marshalling and memory corruption. To
investigate further use native-only debugging. Unhandled exception at
0x000001F303570860 in AWealthOfRows.exe: 0xC0000005: Access violation
reading location 0x000001F30385FB32. The Common Language Runtime
cannot stop at this exception. Common causes include: incorrect COM
interop marshalling and memory corruption. To investigate further use
native-only debugging. The thread '.NET Counter Poller' (35516) has
exited with code 3221225477 (0xc0000005). The thread '.NET TP Gate'
(24688) has exited with code 3221225477 (0xc0000005). The thread 33416
has exited with code 3221225477 (0xc0000005). The thread '.NET
Finalizer' (38504) has exited with code 3221225477 (0xc0000005). The
thread '.NET EventPipe' (23352) has exited with code 3221225477
(0xc0000005). The thread 36944 has exited with code 3221225477
(0xc0000005). The thread 30968 has exited with code 3221225477
(0xc0000005). The thread 3560 has exited with code 3221225477
(0xc0000005). The thread 41012 has exited with code 3221225477
(0xc0000005). The thread 13568 has exited with code 3221225477
(0xc0000005). The thread 22992 has exited with code 3221225477
(0xc0000005). The thread '.NET TP Worker' (38436) has exited with code
3221225477 (0xc0000005). The thread 41284 has exited with code
3221225477 (0xc0000005). The thread 40972 has exited with code
3221225477 (0xc0000005). The thread 40980 has exited with code
3221225477 (0xc0000005). The thread 41972 has exited with code
3221225477 (0xc0000005). The thread 39600 has exited with code
3221225477 (0xc0000005). The thread 41096 has exited with code
3221225477 (0xc0000005). The thread 41968 has exited with code
3221225477 (0xc0000005). The thread 7472 has exited with code
3221225477 (0xc0000005). The thread '.NET ThreadPool IO' (36056) has
exited with code 3221225477 (0xc0000005). The thread 16184 has exited
with code 3221225477 (0xc0000005). The thread 11736 has exited with
code 3221225477 (0xc0000005). The thread '.NET TP Worker' (33156) has
exited with code 3221225477 (0xc0000005). The thread '.NET TP Worker'
(5368) has exited with code 3221225477 (0xc0000005). The thread '.NET
ThreadPool IO' (22304) has exited with code 3221225477 (0xc0000005).
The thread '.NET TP Worker' (42112) has exited with code 3221225477
(0xc0000005). The thread 40516 has exited with code 3221225477
(0xc0000005). The thread '.NET Tiered Compilation Worker' (2424) has
exited with code 3221225477 (0xc0000005). The program '[39016]
AWealthOfRows.exe' has exited with code 3221225477 (0xc0000005)
'Access violation'. `

Я пробовал отладку, но когда возникает проблема. В этом случае C++ вызывает обратный вызов, но до того, как он войдет в область действия функции, выдается исключение, но он сразу же возвращается с кодом ошибки.

В целях отладки я попробовал переключить соглашение о вызовах с cdecl на stdcall, чтобы посмотреть, связано ли это с повреждением стека.

Мои предположения таковы:

  • статические функции, отмеченные [UnmanagedCallersOnly], имеют статический адрес, особенно если определена точка входа.
  • Thread.BeginThreadAffinity(), за которым следует Thread.EndThreadAffinity(), гарантирует, что неуправляемый поток может успешно начать выполнение управляемого кода.

Хорошо знать:

  • Функция вызывается потоком, не созданным на C#, существует множество потоков, вызывающих эту функцию.

Просматривая документацию по указателям функций здесь, я не могу понять, не соблюдаю ли я стандарт или это просто проблема с реализацией C#.

Ссылка не предоставляет никакой информации о совместимости C или C++. Однако я заметил, что nint — это целое число со знаком, специфичное для C#, но вместо этого ваш код C использует void*. Я предлагаю вам использовать ulong на стороне C# и std::uint64_t на стороне C++.

Red.Wave 21.05.2024 12:23

Действительно, C# и C++ сейчас не используют один и тот же тип. до того, как C# имел IntPtr в качестве передаваемого аргумента. Но у nint нет преобразования между IntPtr, как показано здесь Learn.microsoft.com/en-us/dotnet/csharp/language-reference/… std::uint64_t и ulong не будут совпадать, поскольку размер nint отличается на других платформах

Mark Oostveen 21.05.2024 12:49

Что произойдет, если вы используете обычные делегаты (не неуправляемые FP), но кэшируете делегат в поле (в любом случае, если это функция static), улучшит ли это производительность? Также обратный вызов вызывается после возврата EventScheduler_ScheduleLocalEvent? Если это так, код, возможно, был перемещен с тех пор.

Charlieface 21.05.2024 14:09

Хорошая мысль @Charlieface: когда я кэширую делегат, исключений по-прежнему нет. однако производительность по-прежнему намного ниже, чем у FP. Точных показателей у меня сейчас нет. но это было очень похоже на сценарий, в котором я использовал делегатов.

Mark Oostveen 21.05.2024 14:25

@Charlieface Вы здесь говорите о перетасовке данных GC? «Кроме того, обратный вызов вызывается после возврата EventScheduler_ScheduleLocalEvent? Если да, то код, возможно, был перемещен с тех пор». Да, он вызывается после возврата [EventScheduler_ScheduleLocalEvent] и большую часть времени даже из другого потока.

Mark Oostveen 21.05.2024 14:27

@Red.Wave void* имеет размер собственного указателя, такой же, как nint.

Charlieface 21.05.2024 14:40

Ваше предположение: «статические функции, отмеченные [UnmanagedCallersOnly], имеют статический адрес, особенно когда определена точка входа». возможно, это правильно, но в случае с обычными делегатами обязательно нужно убедиться, что делегат не очищен. В любом случае, можете ли вы получить дамп стека и проанализировать его в WinDbg, возможно, вы подскажете, где происходит AV.

Charlieface 21.05.2024 14:41

Я уверен, что Free вызывается только один раз. это проверено в других (не общих) модульных тестах

Mark Oostveen 21.05.2024 15:04

@Charlieface, «но в случае с обычными делегатами вам обязательно нужно убедиться, что делегат не очищен», это натолкнуло меня на некоторые мысли, я сейчас над этим разбираюсь

Mark Oostveen 21.05.2024 15:52

@Charlieface Оказывается, если я возьму адрес делегата* во время статического построения и установлю точку останова перед его использованием, через некоторое время он изменится. Это означает, что статические функции НЕ стабильны в памяти. Работаю над тем, чтобы попытаться исправить это сейчас

Mark Oostveen 21.05.2024 17:18

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

Mark Oostveen 28.05.2024 16:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
11
199
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Оказывается, изменение режимов сборщика мусора навсегда устранило проблему после тщательного тестирования. Такое поведение одинаково для .net8.0 и .net9.0(предварительная версия), выпущенных неделю назад.

Вопрос поднимается здесь в официальном репозитории .net.

Мое решение на данный момент — добавить эти настройки в теги PropertyGroup вашего файла .csproj, прежде чем это будет исправлено в более поздней версии .net.

<ServerGarbageCollection>true</ServerGarbageCollection>
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>

Подробнее о них можно прочитать здесь

Другие вопросы по теме