Windows 7 64位中的递归 [英] Recursion in Windows 7 64 bit
问题描述
我有这个帮助器类
public static class DateTimeHelper
{
public static int GetMonthDiffrence(DateTime date1, DateTime date2)
{
if (date1 > date2)
{
return getmonthdiffrence(date2, date1);
}
else
{
return ((date2.year - date1.year) * 12) + (date2.month - date1.month);
}
}
}
该函数计算两个日期之间的两个月,它确实满足我的要求。
到目前为止,没有问题。
The function calculate the number of months between two dates, it do exactly what I want. So far there is no problem.
问题是,当我使用Windows 7 64位版本时,我总是得到相同的值 0
The problem is when I am on release and windows 7 64 bit I get always the same value "0"
当我深入研究问题时,我意识到在某个时候,由于递归调用,两个参数相等。
When I got deep down the problem, I got aware that at some point, and because of the recursive call the two parameters are equal.
仅当我午餐未构建到调试器上的发行版并在Windows 7 64位系统上吃午餐时,我才会重复此错误。
I repeat that I have this bug only if I lunch the release built un-attached to the debugger and on windows 7 64 bit.
任何人都可以有这个想法吗?如果需要,我需要一些链接以获取更多详细信息。
Can anyone have any idea of this comportment? And if so I need some links to get in more details.
这里是IL代码。 (我认为它可以帮助您了解更多信息)。
Here is the IL Code. (I think it can help to understand more)
.class public auto ansi abstract sealed beforefieldinit Helpers.DateTimeHelper
extends [mscorlib]System.Object
{
// Methods
.method public hidebysig static
int32 GetMonthDiffrence (
valuetype [mscorlib]System.DateTime date1,
valuetype [mscorlib]System.DateTime date2
) cil managed
{
// Method begins at RVA 0x6a658
// Code size 52 (0x34)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call bool [mscorlib]System.DateTime::op_GreaterThan(valuetype [mscorlib]System.DateTime, valuetype [mscorlib]System.DateTime)
IL_0007: brfalse.s IL_0011
IL_0009: ldarg.1
IL_000a: ldarg.0
IL_000b: call int32 Helpers.DateTimeHelper::GetMonthDiffrence(valuetype [mscorlib]System.DateTime, valuetype [mscorlib]System.DateTime)
IL_0010: ret
IL_0011: ldarga.s date2
IL_0013: call instance int32 [mscorlib]System.DateTime::get_Year()
IL_0018: ldarga.s date1
IL_001a: call instance int32 [mscorlib]System.DateTime::get_Year()
IL_001f: sub
IL_0020: ldc.i4.s 12
IL_0022: mul
IL_0023: ldarga.s date2
IL_0025: call instance int32 [mscorlib]System.DateTime::get_Month()
IL_002a: ldarga.s date1
IL_002c: call instance int32 [mscorlib]System.DateTime::get_Month()
IL_0031: sub
IL_0032: add
IL_0033: ret
} // end of method DateTimeHelper::GetMonthDiffrence
}
编辑:
如果您想重现该问题,请使用以下测试程序:
Here is a test program if you wish to reproduce the issue:
class Program
{
static void Main(string[] args)
{
for (int i = 2000; i < 3000; i++)
{
var date1 = new DateTime(i, 1, 1);
var date2 = new DateTime(i + 1, 1, 1);
var monthdiff = DateTimeHelper.GetMonthDiffrence(date2, date1);
if (monthdiff == 0)
Console.WriteLine(string.Format("date1 => {0}, date2 => {1}, diff=> {2}", date2, date1, monthdiff.ToString()));
}
Console.WriteLine("done!");
Console.ReadKey();
}
}
您必须在发布模式和64下构建progect位配置,然后转到生成结果的位置并执行程序。
事前感谢。
我最好的问候。
you have to build the progect on release mode and 64 bit configuration, and then go to the location of the built result and execute the program. Thanks before hand. My best regards.
推荐答案
我可以在Windows 7,.Net 4.5,Visual Studio 2012, x64目标,发布模式,已连接调试器,但禁用了抑制模块加载时的JIT优化。这似乎是尾部调用优化中的一个错误(这就是为什么只在x64上得到它的原因)。
I can replicate this behavior on Windows 7, .Net 4.5, Visual Studio 2012, x64 target, Release mode with debugger attached, but "Suppress JIT optimization on module load" disabled. This seems to be a bug in the tail call optimization (which is why you're getting it only on x64).
IL在这里并不重要,本机代码做。 GetMonthDiffrence()
的相关代码部分是:
IL does not really matter here, the native code does. The relevant part of code for GetMonthDiffrence()
is:
0000005e cmp rdx,rcx
00000061 setg al
00000064 movzx eax,al
00000067 test eax,eax
00000069 je 0000000000000081 // else branch
0000006b mov rax,qword ptr [rsp+68h]
00000070 mov qword ptr [rsp+60h],rax
00000075 mov rax,qword ptr [rsp+60h]
0000007a mov qword ptr [rsp+68h],rax
0000007f jmp 0000000000000012 // start of the method
重要的部分是4 mov
指令。他们尝试交换 [rsp + 68h]
和 [rsp + 60h]
(这是存储参数的位置) ,但是它们做错了,因此两者最终都具有相同的值。
The important part are the 4 mov
instructions. They try to exchange [rsp+68h]
and [rsp+60h]
(which is where the parameters are stored), but they do it incorrectly, so both end up with the same value.
有趣的是,如果我删除对 Console.ReadKey()的调用,
从您的 Main()
中,代码可以正常工作,因为调用 GetMonthDiffrence()
是内联的,在这种情况下不会执行尾调用优化。
Interestingly, if I remove the call to Console.ReadKey()
from your Main()
, the code works fine, because the call to GetMonthDiffrence()
is inlined and the tail call optimization is not performed in that case.
可能的解决方法是添加 [MethodImpl(MethodImplOptions.NoInlining) ]
到您的方法,这似乎禁用了尾部调用优化。
A possible workaround would be to add [MethodImpl(MethodImplOptions.NoInlining)]
to your method, that seems to disable the tail call optimization.
我有在连接上提交了此错误。
这篇关于Windows 7 64位中的递归的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!