【问题标题】:De-Allocation of the Stack memory in .NET.NET 中堆栈内存的解除分配
【发布时间】:2017-01-20 19:09:31
【问题描述】:

今天,我在 CodeProject 上阅读了一篇关于内存管理 .NET 的博客。

网址 - Article

上面写着——

退出方法(乐趣):现在执行控制终于开始了 退出方法。当它通过结束控制时,它清除所有 在堆栈上分配的内存变量。换句话说,所有 与 int 数据类型相关的变量在 堆栈中的“后进先出”时尚。

最大的收获——它没有取消分配堆内存。这段记忆 稍后将由垃圾收集器释放。

据我了解,垃圾收集器仅释放堆内存。那么,谁来释放栈内存呢?

请提出建议。

【问题讨论】:

  • 默认情况下,被调用者负责清理堆栈(stdcall调用约定)。
  • Codeproject.com 内容不受任何形式的体面审查。因此有很多废话和错误,包括这句话的第一段。没有什么是“清除”或“释放”的,当方法返回时,局部变量很容易被遗忘。与 .NET Stack 类的工作方式不同。

标签: c# .net memory-management heap-memory stack-memory


【解决方案1】:

即使没有垃圾回收,堆栈上的值也会自动管理,因为每次进入/退出范围(无论是方法还是语句)时,都会以 LIFO 方式从堆栈中添加和删除项目,这正是变量的原因在 for 循环中定义或 if 语句在该范围之外不可用。

当您用完堆栈上的所有可用空间时,您将收到 StackOverflowException,尽管这几乎可以肯定是无限循环(错误!)或设计不良的系统的症状,其中涉及近乎无休止的递归调用。

【讨论】:

    【解决方案2】:

    简而言之:

    堆栈内存没有被释放。这是一块将被重用的内存。每次一个作用域声明变量(压栈),它会在作用域退出时被弹出。

    所以当一个方法被调用时,参数(一个值或一个引用指针)被压入堆栈(复制)并从堆栈中弹出,当该方法结束。 (弹出只是用内存调整指针(索引))

    这就是为什么 { } 中声明的变量在 } 后面不可用的原因

    这块内存是每个线程的。

    【讨论】:

      【解决方案3】:

      在 .NET 中,变量 位于堆栈上,无论它是否包含数字(值类型)、结构(完全位于堆栈上)或对对象(即对象的托管地址,其中对象本身位于堆上)。

      此外,人们有时会将变量与类字段混淆。字段和所有类成员都位于堆上,在实例化对象时分配的区域内。

      因此,没有任何变量的分配或释放,因为它们只是超出范围的值。变量超出范围后,GC 无法到达实际(堆)对象并最终将其收集。

      【讨论】:

      • 范围不相关。 GC 还可以在方法尚未退出时收集由局部变量引用的对象。它甚至可以在实例方法中收集 this。确保这不会造成任何麻烦是primary job of the jitter
      • 是的,GC 被优化为一旦意识到变量不再被使用就收集对象实例,即使它还没有超出其范围。但是 OP 的问题是关于堆栈“释放”,我怀疑是否存在 CLR 实现,其中堆栈指针在变量真正超出范围之前被移动到任何地方。无论如何,您的评论确实更准确。
      猜你喜欢
      • 2012-12-05
      • 2021-04-08
      • 2018-07-24
      • 2011-10-09
      • 1970-01-01
      • 2011-05-28
      • 2011-08-17
      • 2014-10-26
      相关资源
      最近更新 更多