RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 620026
Accepted
user2455111
user2455111
Asked:2020-01-27 10:43:56 +0000 UTC2020-01-27 10:43:56 +0000 UTC 2020-01-27 10:43:56 +0000 UTC

帮我修正错误

  • 772

有一个对象继承自IEnumerable。MoveNext在此类的方法中,它出现StackOverflowException在带有 的行上Regex。正则表达式本身在文件中查找文本匹配项。值得注意的是,一切都适用于带有 .Net 4.6 的 Windows 10 x64,错误发生在带有 .Net 4.0 的 Windows 7 x64 上。

我有 2 个猜测为什么会这样:

  1. Regex第一:可能是由于.Net 4.0 和 .Net 4.6中方法的实现不同Regex,它在堆栈上占用更多内存,因此出现异常。

  2. 第二:可能Win10和Win7的栈大小不一样。

如何查看当前堆栈大小?如何检查可用堆栈大小?还有什么可能是这个错误的原因?

搜索中的文件数IEnumerable为 2760( _objEnumerator.Count),每个文件都预先加载并作为字符串存储在这个非常IEnumerable. 下面是一个示例代码:

private class MyEnumerator : IEnumerable
{
    public bool MoveNext()
    {
        if (_objEnumerator == null)
        {
            _objEnumerator = _objects.GetEnumerator();
        }

        Match m;

        if (_current == null)
        {
            if (!_objEnumerator.MoveNext())
                return false;

            m = _regex.Match((_objEnumerator.Current).Text); // (_objEnumerator.Current).Text хранит  текст файла, ошибка падает в этой строчке
        }           

        if (m.Success)
        {
           // код выдающий результат
           return true;
        }
        else
        {
           _current = null;
           return MoveNext();
        }
    }
}
c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    VladD
    2020-01-27T16:41:57Z2020-01-27T16:41:57Z

    这个问题,我想,正是因为递归(深度2700,这个很多)。在 .NET 中,似乎从 4.5 开始,他们切换到一个新的 JIT 编译器,该编译器可以检测尾递归,并进行调用tailcall而不是正常的递归调用。结果,堆叠没有被堵塞。


    由于语言不能保证尾递归优化的存在(并且到目前为止似乎不适用于 32 位目标),递归实现是代码中的错误。迭代地重写你的函数。


    澄清:我尝试了与您的代码类似的代码,但它不会在 VS 2015/.NET 4.5/x64/Release 的 IL 代码中生成尾调用。所以这可能不是你的问题。我会尝试进一步调查原因。


    进一步调查:在当前版本的 .NET (4.5) 中,尾递归不需要 IL 前缀tail。示例:这是代码

    class Program
    {
        [MethodImpl(MethodImplOptions.NoOptimization)]
        static void Main(string[] args)
        {
            var t = new Program();
            t.f(1);
            Console.ReadKey();        // здесь можно приаттачить отладчик
            t.f(100000000);
        }
    
        int f(int iterNo)
        {
            new DateTime(2017, 2, 3); // увеличим размер кода функции, чтобы сделать
                                      // хвостовую оптимизацию привлекательной для JIT
            if (iterNo == 0)
                return 0;
            else
                return f(iterNo - 1);
        }
    }
    

    生成以下 IL,不带前缀.tail:

      .method private hidebysig instance int32 
              f(int32 iterNo) cil managed
      {
        // Code size       28 (0x1c)
        .maxstack  8
    //000021: 
    //000022:      int f(int iterNo)
    //000023:      {
    //000024:          new DateTime(2017, 2, 3); // увеличим размер кода функции, чтобы сделать
        IL_0000:  ldc.i4     0x7e1
        IL_0005:  ldc.i4.2
        IL_0006:  ldc.i4.3
        IL_0007:  newobj     instance void [mscorlib]System.DateTime::.ctor(int32,
                                                                            int32,
                                                                            int32)
        IL_000c:  pop
    //000025:                                    // хвостовую оптимизацию привлекательной для JIT
    //000026:          if (iterNo == 0)
        IL_000d:  ldarg.1
        IL_000e:  brtrue.s   IL_0012
    
    //000027:              return 0;
        IL_0010:  ldc.i4.0
        IL_0011:  ret
    
    //000028:          else
    //000029:              return f(iterNo - 1);
        IL_0012:  ldarg.0
        IL_0013:  ldarg.1
        IL_0014:  ldc.i4.1
        IL_0015:  sub
        IL_0016:  call       instance int32 Tailcall.Program::f(int32)
        IL_001b:  ret
      } // end of method Program::f
    

    但是,本机代码f如下所示:

       24:             new DateTime(2017, 2, 3); // увеличим размер кода функции, чтобы сделать
    push        rdi  
    push        rsi  
    sub         rsp,28h  
    mov         rdi,rcx  
    mov         esi,edx  
    mov         ecx,7E1h  
    mov         edx,2  
    mov         r8d,3  
    call        000007FEF1361730  
       25:                                       // хвостовую оптимизацию привлекательной для JIT
       26:             if (iterNo == 0)
    test        esi,esi  
    jne         000007FE932A053D  
       27:                 return 0;
    xor         eax,eax  
    add         rsp,28h  
    pop         rsi  
    pop         rdi  
    ret  
    lea         edx,[rsi-1]                  // вычли 1
    mov         rcx,rdi
    mov         rax,7FE932A0080h  
    add         rsp,28h                      // очистили фрейм
    pop         rsi  
    pop         rdi  
    jmp         rax                          // переход вместо возврата
    

    这意味着可以在 JIT 级别应用尾递归,而无需 IL 编译器的参与。因此,.NET 4.5 具有新的 JIT 编译器这一事实可能会有所帮助。

    无论如何,问题的正确解决方案是以迭代的方式重写代码。

    • 6

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5