如何为托管的可执行.NET更改默认堆栈大小

4
我们发现我们的一个自动生成的程序集在new()时抛出了StackOverflowException异常。这个类有400多个简单属性,在构造函数中初始化(大多数为默认值(string)等)。
我们注意到它在64位上很好,但在32位上会出问题!
我们需要测试是否合理为我们的用例创建一个更大的默认堆栈,以便在重新设计代码生成器时给我们留出余地。
如果可能,我们尤其希望使用app.config的解决方案。但我是现实主义者,所以任何东西都可以。
关于堆栈溢出的原因。我们已经将错误缩小到了相关的构造函数。我的第一印象也是无限递归的类型。然而,我们使用一个3行的控制台应用程序重现了这个错误:
创建一个类的空实例。 调用类上的非静态方法(Clone),它的第一项工作是创建一个空实例,准备将属性传递给它。 当它达到第二个构造函数时就会失败。
现在使用.net源代码进行调试,我们看到堆栈溢出在Guid.NewGuid()中,它被作为第二个参数传递给构造函数。实际的代码行是调用本地的CoCreateGuid()调用。
因此,虽然这可能是CoCreateGuid()中的一个错误,但我们想排除我们的代码问题。我的第一个想法是大幅增加堆栈的大小,看看这个错误是否会再次发生。然后,由于我认为我们可以控制所有用例,就将构造函数替换为对象初始化——我认为这可以减轻对堆栈的压力。
注意:我们可以通过从类中删除一个int属性来防止错误发生。

1
好的,所以我在没有查看建议的重复内容 http://stackoverflow.com/questions/1042347/how-do-you-change-default-stack-size-for-managed-executable 的情况下投票支持关闭。对此我感到抱歉。由于这个问题已经得到了回答,而另一个问题还没有,我认为我们应该保留这个问题并关闭另一个问题。 - Emil H
糟糕,重复了,是浏览器卡顿的原因,因为我自己点击返回以为要添加更多信息,但显然它已经发布了。 - Preet Sangha
我知道这很老,但是...可能它没有使用尾递归吗?如果你在方法中将递归函数调用作为最后一个操作,它将使用.NET尾递归,并且不会填充你的堆栈。 - Aridane Álamo
1个回答

4
您可以使用 editbin更改可执行文件的堆栈大小。据我所知,您不能在app.config中这样做。
另一个选项(也在该页面上提到)是创建一个带有“正确”堆栈大小的新线程。该页面提到了这种方法的优缺点。
但我会感到惊讶,如果仅在构造函数中设置400个属性就是问题的原因...那将是一个巨大的堆栈框架-但除非您在堆栈上有几个大堆栈框架,否则我认为它会没问题。另一个可能性是您在某个地方存在无限递归:)
编辑:另一种替代建议...
您的构造函数中可能有很多局部变量吗? (否则,它不应比任何其他调用占用更多堆栈。)是否可以将构造函数拆分为多个方法,每个方法设置(例如)20个字段?尽管如此,如果字段是只读的,这将是棘手的。
如果你能给我们一个构造函数的具体样式,这将帮助很多。您可能还想使用ildasm来查看它声称该构造函数的堆栈大小。
只是为了确认,这是一个类而不是一个结构体,对吗?

谢谢您的快速回答。我已经在问题中回答了您的查询。 - Preet Sangha
感谢提供的附加信息。确定是一个类,而不是一个结构体。我会在今天上午调查多种初始化方法。 - Preet Sangha
谢谢Jon。Editbin暂时为我们工作 - 在我们重新设计这个生成过程期间。 - Preet Sangha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接