在C#中检查堆栈大小 [英] Checking stack size in C#

查看:506
本文介绍了在C#中检查堆栈大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法来检查线程在C#堆栈大小?

Is there a way to check threads stack size in C#?

推荐答案

这是如果你要问,你买不起(雷蒙德陈先说的。)如果code取决于是否有足够的堆栈空间的程度,它首先检查,它可能是值得的重构它使用一个明确的 堆栈< T> ,而不是反对。有优点在约翰的有关使用替代分析器评论。

This is a case of if you have to ask, you can't afford it (Raymond Chen said it first.) If the code depends on there being enough stack space to the extent that it has to check first, it might be worthwhile to refactor it to use an explicit Stack<T> object instead. There's merit in John's comment about using a profiler instead.

这表示,事实证明,有估计剩余的堆栈空间的一种方式。这不是precise,但它足够有用的评估如何靠近你是底部的目的。主要是基于一个excellent本文由Joe达菲的。

That said, it turns out that there is a way to estimate the remaining stack space. It's not precise, but it's useful enough for the purpose of evaluating how close to the bottom you are. The following is heavily based on an excellent article by Joe Duffy.

我们知道(或会使假设)是:

We know (or will make the assumptions) that:


  1. 栈内存是在一个连续的块分配的。

  2. 堆栈增长'向下',从高地址向低地址。

  3. 系统需要接近分配的堆栈空间的底部一定的空间,让出的堆栈异常优雅地处理。我们不知道确切的预留空间,但我们会尝试保守约束它。

根据这些假设,我们可以PInvoke的<一个href=\"http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k%28CONSOLEAPPLICATION1.PROGRAM.VIRTUALQUERY%29;k%28VIRTUALQUERY%29;k%28TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22%29;k%28DevLang-CSHARP%29&rd=true\">VirtualQuery以获得分配的堆栈的起始地址,并从一些堆栈分配变量的地址减去它(不安全code获得的。)进一步减去我们的系统需要在堆的底部将得到空间的估计我们的可用空间的估算。

With these assumptions, we could pinvoke VirtualQuery to obtain the start address of the allocated stack, and subtract it from the address of some stack-allocated variable (obtained with unsafe code.) Further subtracting our estimate of the space the system needs at the bottom of the stack would give us an estimate of the available space.

在code下面通过调用递归函数,并写出预计剩余的堆栈空间,以字节为单位说明了这一点,因为它有云:

The code below demonstrates this by invoking a recursive function and writing out the remaining estimated stack space, in bytes, as it goes:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplication1 {
    class Program {
        private 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;
        }

        private const uint STACK_RESERVED_SPACE = 4096 * 16;

        [DllImport("kernel32.dll")]
        private static extern int VirtualQuery(
            IntPtr                          lpAddress,
            ref MEMORY_BASIC_INFORMATION    lpBuffer,
            int                             dwLength);


        private unsafe static uint EstimatedRemainingStackBytes() {
            MEMORY_BASIC_INFORMATION    stackInfo   = new MEMORY_BASIC_INFORMATION();
            IntPtr                      currentAddr = new IntPtr((uint) &stackInfo - 4096);

            VirtualQuery(currentAddr, ref stackInfo, sizeof(MEMORY_BASIC_INFORMATION));
            return (uint) currentAddr.ToInt64() - stackInfo.AllocationBase - STACK_RESERVED_SPACE;
        }

        static void SampleRecursiveMethod(int remainingIterations) {
            if (remainingIterations <= 0) { return; }

            Console.WriteLine(EstimatedRemainingStackBytes());

            SampleRecursiveMethod(remainingIterations - 1);
        }

        static void Main(string[] args) {
            SampleRecursiveMethod(100);
            Console.ReadLine();
        }
    }
}

这是第10行输出(英特尔的x64,.NET 4.0,调试)的。鉴于1MB缺省堆栈大小,计数显得似是而非。

And here are the first 10 lines of output (intel x64, .NET 4.0, debug). Given the 1MB default stack size, the counts appear plausible.

969332
969256
969180
969104
969028
968952
968876
968800
968724
968648

有关简洁起见,code以上假设4K的页面大小。虽然这适用于x86和x64真实的,它可能不适合其它支持CLR的体系结构是正确的。你可以的PInvoke进入的GetSystemInfo 以获取本机的页面大小(dwPageSize 结构的)。

For brevity, the code above assumes a page size of 4K. While that holds true for x86 and x64, it might not be correct for other supported CLR architectures. You could pinvoke into GetSystemInfo to obtain the machine's page size (the dwPageSize of the SYSTEM_INFO struct).

请注意,这种技术没有特别的便携的,也不是未来的证明。使用的PInvoke限制了这种方法的Windows主机的效用。有关CLR堆栈增长的连续性和方向的假设可能保持为present Microsoft实现真。但是, CLI标准我(可能有限)阅读(共同语言基础设施,PDF,长时间阅读)似乎并不需要尽可能多的线程堆栈。至于CLI而言,每个方法调用需要一个堆栈帧; ,这一点也不在乎,但是如果堆栈向上生长,如果,如​​果栈帧是在堆上分配的局部变量堆栈从返回值堆分开的。

Note that this technique isn't particularly portable, nor is it future proof. The use of pinvoke limits the utility of this approach to Windows hosts. The assumptions about the continuity and direction of growth of the CLR stack may hold true for the present Microsoft implementations. However, my (possibly limited) reading of the CLI standard (common language infrastructure, PDF, a long read) does not appear to demand as much of thread stacks. As far as the CLI is concerned, each method invocation requires a stack frame; it couldn't care less, however, if stacks grow upward, if local variable stacks are separate from return value stacks, or if stack frames are allocated on the heap.

这篇关于在C#中检查堆栈大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆