抖动优化器可能是此问题的根源。下面是一个例子:
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寄存器存储输入变量。注意它从来没有被设置回null,它总是存储对最后输入的字符串的引用。优化器已删除空分配语句。垃圾收集器从抖动中获得生命提示,它会说在循环期间引用是活动的。
问题发生在第二次和随后的传递,当你从不输入东西,然后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);
}
没有别的东西有它的参考? – 2011-05-24 03:52:57
你能显示项目的所有用法吗? – 2011-05-24 04:04:02
分析器显示对GC根目标的引用,这是其中之一。我在github上发布的例子显示了这个问题,并且在循环中有* only *引用。 – SimonC 2011-05-24 04:19:31