Вероятным источником этой проблемы является оптимизатор джиттера. Вот пример:
class Program {
static void Main(string[] args) {
while (true) {
var input = Console.ReadLine();
Console.WriteLine(input);
input = null;
}
}
}
Создает этот машинный код:
while (true) {
var input = Console.ReadLine();
00000000 push ebp ; setup stack
00000001 mov ebp,esp
00000003 push esi
00000004 call 6E0208F0 ; Console.In property getter
00000009 mov ecx,eax
0000000b mov eax,dword ptr [ecx]
0000000d call dword ptr [eax+64h] ; TextReader.ReadLine()
00000010 mov esi,eax ; assign input variable
Console.WriteLine(input);
00000012 call 6DB7BE38 ; Console.Out property getter
00000017 mov ecx,eax
00000019 mov edx,esi
0000001b mov eax,dword ptr [ecx]
0000001d call dword ptr [eax+000000D8h] ; TextWriter.WriteLine()
00000023 jmp 00000004 ; repeat, note the missing null assigment
В регистре esi хранится переменная input . Обратите внимание, что он никогда не возвращается к нулю, он всегда сохраняет ссылку на последнюю введенную строку. Оптимизатор удалил пустой оператор присваивания. Сборщик мусора получает подсказки времени жизни от дрожания, он будет говорить, что ссылка жива в течение всего цикла.
Проблема возникает на втором и последующем проходе, когда вы никогда не набираете что-либо, тогда ReadLine () блокируется (аналогично вашей очереди блокировки), а значение регистра esi продолжает ссылаться на строку. Он никогда не будет собираться мусором в течение цикла, по крайней мере, пока он не будет переназначен.
Нет чистого решения для этого. Вот ужасный:
[MethodImpl(MethodImplOptions.NoInlining)]
public static void NullReference<T>(ref T obj) where T : class {
obj = null;
}
и использование:
while (true) {
var input = Console.ReadLine();
Console.WriteLine(input);
NullReference(ref input);
}