有没有一种方法可以在C#中检查线程的堆栈大小?
有没有一种方法可以在C#中检查线程的堆栈大小?
Stack<T>
对象可能是值得的。 John的评论中有使用性能分析器的价值。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行(intel x64,.NET 4.0,debug)。考虑到默认的1MB堆栈大小,计数似乎是合理的。
969332
969256
969180
969104
969028
968952
968876
968800
968724
968648
我在这里添加这个答案以便将来参考。
Oren的答案回答了SO的问题(通过评论细化),但它没有表明栈实际上分配了多少内存。要获得该答案,您可以使用Michael Ganß的答案,我已经更新了一些更新的C#语法。
public static class Extensions
{
public static void StartAndJoin(this Thread thread, string header)
{
thread.Start(header);
thread.Join();
}
}
class Program
{
[DllImport("kernel32.dll")]
static extern void GetCurrentThreadStackLimits(out uint lowLimit, out uint highLimit);
static void WriteAllocatedStackSize(object header)
{
GetCurrentThreadStackLimits(out var low, out var high);
Console.WriteLine($"{header,-19}: {((high - low) / 1024),4} KB");
}
static void Main(string[] args)
{
WriteAllocatedStackSize("Main Stack Size");
new Thread(WriteAllocatedStackSize, 1024 * 0).StartAndJoin("Default Stack Size");
new Thread(WriteAllocatedStackSize, 1024 * 128).StartAndJoin(" 128 KB Stack Size");
new Thread(WriteAllocatedStackSize, 1024 * 256).StartAndJoin(" 256 KB Stack Size");
new Thread(WriteAllocatedStackSize, 1024 * 512).StartAndJoin(" 512 KB Stack Size");
new Thread(WriteAllocatedStackSize, 1024 * 1024).StartAndJoin(" 1 MB Stack Size");
new Thread(WriteAllocatedStackSize, 1024 * 2048).StartAndJoin(" 2 MB Stack Size");
new Thread(WriteAllocatedStackSize, 1024 * 4096).StartAndJoin(" 4 MB Stack Size");
new Thread(WriteAllocatedStackSize, 1024 * 8192).StartAndJoin(" 8 MB Stack Size");
}
}
有趣的是(也是我发布这篇文章的原因),在使用不同配置运行时的输出结果。供参考,我使用的是 Windows 10 企业版(版本号为 1709)64 位操作系统,并且使用 .NET Framework 4.7.2 运行(如果有影响的话)。
Main Stack Size : 1024 KB
Default Stack Size : 1024 KB // default stack size = 1 MB
128 KB Stack Size : 256 KB // minimum stack size = 256 KB
256 KB Stack Size : 256 KB
512 KB Stack Size : 512 KB
1 MB Stack Size : 1024 KB
2 MB Stack Size : 2048 KB
4 MB Stack Size : 4096 KB
8 MB Stack Size : 8192 KB
Main Stack Size : 4096 KB
Default Stack Size : 4096 KB // default stack size = 4 MB
128 KB Stack Size : 256 KB // minimum stack size = 256 KB
256 KB Stack Size : 256 KB
512 KB Stack Size : 512 KB
1 MB Stack Size : 1024 KB
2 MB Stack Size : 2048 KB
4 MB Stack Size : 4096 KB
8 MB Stack Size : 8192 KB
这些结果并不特别令人震惊,因为它们与文档一致。然而,有点令人惊讶的是,在Release | Any CPU配置下,默认堆栈大小为1 MB,并且未选中Prefer 32位选项,则在64位操作系统上作为64位进程运行。我本来以为在这种情况下,默认堆栈大小应该是4 MB,就像Release | x64配置一样。
无论如何,我希望这对那些想了解.NET线程的堆栈大小的人有所帮助,就像我一样。
<TargetFramework>net5.0</TargetFramework>
(以及早期版本的 .NET Core),main 函数的输出为 "Main Stack Size : 1536 KB"。因此,.NET Core 的堆栈大小增加了 50%。然而,当我将配置更改为 Release|x64 时,该输出没有发生变化,这是出乎意料的。我使用 Visual Studio 中的 Configuration Manager 进行了实验。 - Scott Hutchinson