GC и неуправляемый код

Я работают с OpenCL в C# через Cloo. Для серии вычислений я создаю массив из буферов:

ComputeKernel[] computeKernels = new ComputeKernel[TempsByStep.Count];
ComputeBuffer<double>[] Temps = new ComputeBuffer<double>[TempsByStep.Count];
ComputeBuffer<double>[] Steps = new ComputeBuffer<double>[TempsByStep.Count];
ComputeBuffer<double>[] Outputs = new ComputeBuffer<double>[TempsByStep.Count];

который инициализирую в цикле

for (int i = 0; i < TempsByStep.Count; i++)
{
    //создаем буферы обмена
    computeKernels[i] = CalculateJIntegralSingleStep.CreateKernel("CalcdJIntegral");
    Temps[i] = new ComputeBuffer<double>(Context,
        ComputeMemoryFlags.UseHostPointer | ComputeMemoryFlags.ReadOnly,
        TempsByStep[i].ToArray());
    Steps[i] = new ComputeBuffer<double>(Context
        , ComputeMemoryFlags.UseHostPointer | ComputeMemoryFlags.ReadOnly,
        new double[] { Accuracy[i] });
    output_buffer[i] = new double[TempsByStep[i].Count - 1];
    Count[i] = TempsByStep[i].Count - 1;
    Outputs[i] = new ComputeBuffer<double>(Context,
        ComputeMemoryFlags.UseHostPointer | ComputeMemoryFlags.ReadWrite,
       output_buffer[i]);
    //конфигурируем кернел
    computeKernels[i].SetMemoryArgument(1, Temps[i]);
    computeKernels[i].SetMemoryArgument(2, Steps[i]);
    computeKernels[i].SetMemoryArgument(3, Outputs[i]);
    //Блокируем удаление
    GC.KeepAlive(computeKernels[i]);
    GC.KeepAlive(Temps[i]);
    GC.KeepAlive(Steps[i]);
    GC.KeepAlive(Outputs[i]);
    GC.KeepAlive(output_buffer[i]);
    GC.KeepAlive(Count[i]);
}

после так же защищаю сами массивы

//Блокируем удаление
GC.KeepAlive(computeKernels);
GC.KeepAlive(Temps);
GC.KeepAlive(Steps);
GC.KeepAlive(Outputs);

И передаю в метод, который это использует с ref

return CalculateJF(variables[0], Count, ref computeKernels, ref Outputs, x);

в самом конце удаляю в цикле

for (int i = 0; i < TempsByStep.Count; i++)
{
    computeKernels[i].Dispose();
    Temps[i].Dispose();
    Steps[i].Dispose();
    Outputs[i].Dispose();
}

Проблема в том, что в 3 из 10 случаев программа через случайную итерацию расчета благополучно вылетает без какого то exception вообще. Код завершения намекает на "status stack buffer overrun", 0xc0000409. Все попытки что либо исправить сводятся именно к этому участку кода. Я думаю, что GC удаляет объекты из памяти, т.к. например Steps больше нигде не фигурирует. KeepAlive помог, т.к. раньше вылетало с первого раза, но проблема как была, так и осталась. Как можно заставить GC игнорировать эти переменный до тех пор пока я сам не вызову Dispose?


Ответы (1 шт):

Автор решения: TheCoolKuid

Проблема действительно оказалась с удалением объектов GC. Объект, который может быть удален, нужно поместить в конструкцию, указанную тут: https://stackoverflow.com/questions/6005865/prevent-net-garbage-collection-for-short-period-of-time Нужно очень тщательно выбирать код, который будет помещено в область с отключенным GC, т.к. случайная ошибка может вызвать stack overflow exception

→ Ссылка