【问题标题】:Where is task stack allocated in C#?C#中的任务堆栈分配在哪里?
【发布时间】:2016-08-05 11:32:29
【问题描述】:

我们都知道诸如 Task.RunParallel.ForEach 之类的方法。 它们中的每一个都创建根据选项在单独的线程中或在线程池中的线程中运行的任务。但是,他们的堆栈在哪里?在某个代堆中还是有专门的地方供他们使用?

例如,我可以创建 1000 个任务,它们的堆栈在哪里?如果我调用 GC.Collect(),他们的物理地址会在某个时候移动吗?

【问题讨论】:

  • 这对于特定的 CLR 实现、底层操作系统甚至 CPU 架构来说都是非常具体的。例如,Windows 对分配(和增长)线程堆栈有特定的支持,这与 x86/x64 内存管理的工作方式一致。
  • 确实如此。 C# 语言中几乎没有要求存在任何堆栈(实际上只是堆栈分配 - 在 C# 语言规范中只有 44 次出现 stack,其中一半是名为 Stack 的示例类)

标签: c# multithreading


【解决方案1】:

堆栈是一个纯粹的非托管实现细节。处理器需要一个堆栈来完成任何事情,没有它它就无法有意义地执行任何代码。它与线程紧密相关,线程是普通 CLR 主机上的另一个纯非托管细节。

它位于操作系统内核在创建线程时决定分配它的内存中,它是随机的。故意随机给恶意软件带来困难,堆栈是将数据转换为恶意代码的一种有吸引力的方式。不仅位置是随机的,而且堆栈开始的堆栈段内的确切偏移量也是随机的。

它在创建后永远不会移动,GC 不会修补它。它确实需要知道它,对象根可以存储在堆栈中。因此,可靠的堆栈遍历是 .NET 的一项硬性要求,这也是当程序因未处理的异常而死时,CLR 始终可以生成良好堆栈跟踪的基本原因。堆栈空间不足是一个严重的问题,处理器无法继续执行代码。严重到可以用那个问题来命名程序员的网站:)

【讨论】:

    【解决方案2】:

    基于TaskScheduler 执行的委托的任务在TaskScheduler 使用的任何堆栈上运行。默认调度程序使用线程池线程。这些(大部分)是普通的 .NET 线程。

    特别是,Task.Run 创建了这样一个基于默认调度程序的任务。

    基于TaskCompletionSource 的任务不执行代码,也不需要堆栈。它们是根据一些外部条件完成的,例如 IO 完成或计时器计时。

    .NET 没有对基于堆的堆栈或“绿色线程”的内置支持。你一般不会在实际代码中找到这样的东西。

    【讨论】:

      猜你喜欢
      • 2014-10-04
      • 1970-01-01
      • 1970-01-01
      • 2011-12-10
      • 2010-10-26
      • 2013-01-10
      • 2013-07-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多