我试图弄清楚C#编译器如何处理尾调用.
(答案:他们不是.但是64位JIT会做TCE(尾部呼叫消除).限制适用.)
所以我使用递归调用编写了一个小测试,它打印了在StackOverflowException杀死进程之前调用它的次数.
class Program
{
static void Main(string[] args)
{
Rec();
}
static int sz = 0;
static Random r = new Random();
static void Rec()
{
sz++;
//uncomment for faster, more imprecise runs
//if (sz % 100 == 0)
{
//some code to keep this method from being inlined
var zz = r.Next();
Console.Write("{0} Random: {1}\r", sz, zz);
}
//uncommenting this stops TCE from happening
//else
//{
// Console.Write("{0}\r", sz); …Run Code Online (Sandbox Code Playgroud) 我的问题很简单明了:如果我有1MB的RAM分配给程序的堆栈,我可以获得开始和结束的地址,或者开始和长度吗?
我正在使用Visual Studio 2013.
有没有办法在c ++中知道最大递归深度而不显式调用递归直到它崩溃?
我已经看到它受到堆栈大小的限制.也许在特定的递归级别找到堆栈中的可用空间量是有用的.可能吗?
在Linux上,使用C,假设我有一个动态确定的n命名,我必须在一个数组(int my_array[n])中存储的元素数量只是一段时间,比如一个函数调用,其中被调用的函数只使用很少的内存(一些百字节).
大部分n是小的,十分之一.但有时n可能很大,高达1000或1000'000.
我如何计算我的堆栈是否可以保存n*o + p字节而不会溢出?
基本上:我的堆栈上剩下多少字节?
在C中有两种创建数组的方法:
int array[100];
Run Code Online (Sandbox Code Playgroud)
和
int * array = malloc(sizeof(int)*100);
Run Code Online (Sandbox Code Playgroud)
使用第二个语句很容易检查是否有足够的内存可用于创建数组,例如:
if(array == NULL){
goto OutOfMemory;
}
Run Code Online (Sandbox Code Playgroud)
但是你怎么检查第一个成功的?假设这是在微控制器而不是计算机上运行的.
许多C/C++/Fortran和其他程序员都会遇到"堆栈溢出"错误.我的问题是,是否有工具,程序或简单的代码片段,允许我们在程序运行时监视或检查堆栈的大小?这可能有助于确定堆栈的累积位置并最终导致溢出.
我刚才注意到,当我使用 pthread_create() 生成线程时,我为线程设置自定义堆栈大小的请求似乎被忽略了。特别是,如果我从生成的线程中调用 pthread_attr_getstacksize() ,它总是报告默认堆栈大小,无论我要求什么。
这种行为在 Linux 和 MacOS/X 下都会出现,所以我怀疑我做错了什么,但我不知道它是什么。
要重现该问题,请编译并运行下面的代码(通过“g++ stack_test.cpp -lpthread ; ./a.out”)。它会尝试一堆不同的堆栈大小,如果其请求未得到满足,则会发出抱怨。有问题的输出如下所示:
Jeremys-Mini:~ lcsuser1$ ./a.out
Testing creation of a thread with stack size: 8192
ThreadFunc: ERROR, wrong stack size! (Requested: 8192, got: 524288)
Testing creation of a thread with stack size: 16384
ThreadFunc: ERROR, wrong stack size! (Requested: 16384, got: 524288)
Testing creation of a thread with stack size: 24576
ThreadFunc: ERROR, wrong stack size! (Requested: 24576, got: 524288)
[...]
Testing creation of a thread with stack …Run Code Online (Sandbox Code Playgroud) 背景
我们一直在使用从Joe Duffy的"Windows上的Concurrent Programming"(第149页)中逐字复制的一些代码,这些代码已经生产了一年多.代码(如下所示)在我们的Asp.Net Web应用程序中用于探测是否有足够的堆栈空间.我们的网站允许用户使用简单的专有脚本语言编写自己的网页和控制逻辑脚本 - 用户可以编写令人讨厌的东西并导致堆栈溢出异常,因此我们使用Duffy的代码示例来停止执行错误的脚本无法捕获的StackOverflow异常会占用整个IIS AppPool.这一直很有效.
问题
今天下午突然我们的日志填满了System.OverflowException错误.我们对该服务器的每个请求都有相同的异常.一个快速的IIS重置解决了这个问题.
异常类型:System.OverflowException
异常消息:算术运算导致溢出.
堆栈跟踪:在C:\ SVN\LiquidHtml\Trunk\LiquidHtmlFlowManager\StackManagement.cs中的LiquidHtmlFlowManager.StackManagement.CheckForSufficientStack(UInt64字节)处的System.IntPtr..ctor(Int64值)处:第47行
代码:
public static class StackManagement
{
[StructLayout(LayoutKind.Sequential)]
struct MEMORY_BASIC_INFORMATION
{
public uint BaseAddress;
public uint AllocationBase;
public uint AllocationProtect;
public uint RegionSize;
public uint State;
public uint Protect;
public uint Type;
};
//We are conservative here. We assume that the platform needs a
//whole 16 pages to respond to stack overflow (using an X86/X64
//page-size, not IA64). That's 64KB, which means that for very
//small stacks …Run Code Online (Sandbox Code Playgroud) 我很难看到如何在C++中安全地分配堆栈数组.
通常人们这样做:
int a[hugeNumber]{0}; //declare,allocate,inti to 0.
Run Code Online (Sandbox Code Playgroud)
由于堆栈溢出,这很容易失败.
我想以某种方式拆分声明和分配,并在try catch中进行分配.
显然这不起作用,因为数组在try之外是不可访问的.
try{
int a[hugeNumber];
}
catch(std::bad_alloc& e)
{
}
//code here can't use a because of scope.
Run Code Online (Sandbox Code Playgroud)
如果你只能通过分离声明和分配以安全的方式分配基于堆的数组,那么生成代码就无法使用基于堆栈的数组,不是吗?
我认为这主要是一种心理锻炼.我一直在考虑它,我没有看到任何地方说明问题.largeNumber在现实中是相对的.实际上,即使是正常的数字也可能导致分配失败,并且因为似乎没有办法安全地分配基于堆栈的数组,我要求显而易见的......"可以在生产代码中使用基于堆栈的数组吗?".我问以防万一有一些我不知道的语法.我真的很感激输入.