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