增加主程序的堆栈大小或为递归代码块创建一个具有更大堆栈大小的新线程?

Posted

技术标签:

【中文标题】增加主程序的堆栈大小或为递归代码块创建一个具有更大堆栈大小的新线程?【英文标题】:Increase stack size of main program or create a new thread with larger stack size for recursive code blocks? 【发布时间】:2019-10-21 21:46:19 【问题描述】:

我有一个后续问题 What is the stack size of a BackgroundWorker DoWork Thread? Is there way to change it?

我是否应该使用以下构建后事件来增加主程序的堆栈大小:

"$(DevEnvDir)..\..\VC\bin\editbin.exe" /STACK:8388608 "$(TargetPath)"

还是应该将我的递归代码块封装在具有更大堆栈大小的新线程中?

Thread thread = new Thread(delegate()

    // do work with larger stack size
, 8192 * 1024);
thread.Start();
thread.Join();

具有大量递归的代码来自英特尔 MKL 的 LAPACKE_dtrtri 函数,我调用了 DLLImport。所以我无法更改此代码。我可以更改堆栈大小以避免堆栈溢出错误。

为我的主程序分配更大的堆栈大小有什么缺点?

为此计算创建具有更大堆栈大小的新线程有什么缺点?

哪种解决方案更好?

合理的堆栈大小是多少? 8 MB、16 MB、32 MB 或 64 MB(如 MATLAB)?该程序在具有至少 16 GB RAM(最高 256 GB)的计算机上运行。

注意:对于我的应用程序的 99%,默认堆栈大小为 4 MB(64 位)就足够了,但另外 1% 使用的是高度递归的外部代码。

【问题讨论】:

这些都不是。正如 Hans Passant 在其他问题矩阵反转不是火箭科学中所评论的那样,堆栈大小由操作系统控制,没有操作系统 会给你那么多堆栈空间。大数组不在堆栈上分配,16MB很大。 MATLAB 在处理大型数组时不会冻结操作系统,如果它使用数百 MB 的堆栈空间会发生这种情况 无论如何,首先编写 SIMD 命令是为了处理多媒体文件,这些文件比您描述的数组大几倍。使用它们的程序是通过对所有数据使用递归。他们处理数据流,甚至禁用 CPU 缓存,因为他们知道不再需要相同的数据,那么为什么在只有一个有用的情况下执行 两次 读取? @PanagiotisKanavos 如果您有大型矩​​阵,例如 70000x70000(约 36.5 GB),这不再是小事了。我需要注意几个限制:例如<gcAllowVeryLargeObject> 和***.com/questions/47830510/…。所以我想出了直接调用英特尔 MKL。我的数组不在堆栈上,但英特尔 MKL 的计算例程是递归的。 你被这个问题搞得有点麻木了。除了您已经找到但忘记归因的所有 SO 帖子之外,如果您想处理巨型矩阵,那么请务必要求 64 位代码执行,以便您有足够的地址空间。项目 > 属性 > 构建选项卡。要求 1GB 堆栈并非不合理。 没关系,掷硬币。如果它没有落在最容易做到的一侧,那么再次翻转。您必须假设 MATLAB 是一个经过良好测试的程序,它不依赖于笨拙的 fortran 代码。 【参考方案1】:
哪种解决方案更好? 哪种解决方案更好?

第一种方法在构建后事件中使用 editbin 在使用强名称密钥对程序集进行签名时失败。使用editbin 更改程序集后,签名程序集的验证将失败。 sn.exe -v assembly.exe 将返回 Failed to verify assembly -- Strong name validation failed ...

参见:

Is an assembly signed with a strong name before or after the post-build event?

使用AfterCompile 事件并退出程序集是一种解决方法(我现在正在使用它)。项目文件应包含以下几行:

  <Target Name="AfterCompile">
    <Exec Command="
&quot;$(DevEnvDir)..\..\VC\bin\editbin.exe&quot; /STACK:16777216 &quot;$(ProjectDir)obj\$(ConfigurationName)\$(TargetFileName)&quot;
&quot;$(FrameworkSDKDir)bin\NETFX 4.5.1 Tools\sn.exe&quot; -Ra &quot;$(ProjectDir)obj\$(ConfigurationName)\$(TargetFileName)&quot; &quot;$(SolutionDir)\STRONGNAME.snk&quot;
" />
  </Target>
  <PropertyGroup>
    <PostBuildEvent>REM "See AfterCompile for stack size and resigning"</PostBuildEvent>
  </PropertyGroup>

当我阅读以下答案时,我意识到编译后事件:https://***.com/a/22617361/7556646

第二种方法但对于空洞程序,而不仅仅是对于递归代码块,看起来像这样:

static class Program

    [STAThread]
    static void Main(string[] args)
    
        Thread thread = new Thread(delegate()
        
            Main2(args);
        , 16 * 1024 * 1024);
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        thread.Join();
    

    static void Main2(string[] args)
    
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(app);
    

第二种方法的缺点是 BackgroundWorker DoWork 事件的堆栈大小仍然是 1 MB(32 位或任何)或 4 MB(64 位)。

参见:

What is the stack size of a BackgroundWorker DoWork Thread? Is there way to change it?
为此计算创建具有更大堆栈大小的新线程有什么缺点? 合理的堆栈大小是多少?

请参阅 Hans Passant 的 cmets。

【讨论】:

以上是关于增加主程序的堆栈大小或为递归代码块创建一个具有更大堆栈大小的新线程?的主要内容,如果未能解决你的问题,请参考以下文章

在 python 2.7 中增加递归限制和堆栈大小

如何增加python中的堆栈大小

单声道下的堆栈大小

我正在尝试增加 Visual Studio 2017 中的堆栈大小

有没有办法增加c#中的堆栈大小?

堆栈溢出一般是由啥原因导致的?