【问题标题】:Is it possible that memory leak can occurs at stack in .NET also?.NET中的堆栈是否也可能发生内存泄漏?
【发布时间】:2010-02-25 08:18:34
【问题描述】:

内存泄漏是,当应用程序中有未使用的内存并且GC可以收集它时,通常如果在应用程序中的某些地方我们保留不需要的对象的强引用,并且GC将能够找到路径(直接和间接)所以它可以释放这个对象,但是这对于堆内存分配中的引用类型都是正确的。

但是堆栈呢?据我所知,GC 不会负责清理堆栈,它会在函数返回时自动清理。

所以我的问题是,堆栈中是否也有可能发生内存泄漏?如果是,那么在什么情况下以及避免这种泄漏的最佳做法是什么。

【问题讨论】:

    标签: c# .net memory-leaks


    【解决方案1】:

    如果您正在编写递归函数来保留对子递归调用中不需要的大数据的堆栈本地引用,那么这是一种空间泄漏,但在实践中出现这种问题是非常罕见的.

    更一般地说,如果你有类似的东西

    Main() {
        var s = ReadInAGiganticString();   // say 10 Megs long
        Server(s.Substring(0,5));          // but I only care about first 5 chars
    }
    Server(s) {
        while(true) { ... }                // but 10M is on stack forever
    }
    

    那么这是一种堆栈空间泄漏,但同样在实践中不太可能。修复很简单:

    Main() {
        var s = ReadInAGiganticString();
        var t = s.Substring(0,5);
        s = null;                         // the fix
        Server(t);
    }
    Server(s) {
        while(true) { ... }
    }
    

    一般来说,如果您在调用之前的堆栈上有一个巨大的变量,该变量将持续“很长时间”并且不再使用该变量,您可以将其清空以确保它可以在之前被 GC进入“长”电话。

    (优化器可能会根据可达性分析为您执行此操作。)

    请注意,上面的答案是针对以堆栈为根的堆分配对象的引用。另一方面,如果您有堆栈分配的内存(例如,一个巨大的结构或 stackalloc 事物),那么修复就不是那么容易了,但这在实践中甚至更罕见(谁曾创建过巨型结构?)。

    【讨论】:

    • 只有对字符串的引用在栈上,字符串本身驻留在堆上。
    【解决方案2】:

    如果未能正确释放非托管资源,可能会发生内存泄漏。所以我担心如果你将一个托管对象发送给一个方法并且这个对象包装了一个非托管资源并且它无法正确释放非托管资源,那么就会出现内存泄漏。堆栈将释放托管引用,但非托管资源将保持活动状态。

    【讨论】:

      【解决方案3】:

      在堆栈中分配的变量在块结束后被销毁。因此,内存泄漏不可能累积。床的做法是创建一个仅在该块之外的给定块中使用的变量

      【讨论】:

        【解决方案4】:

        正如您所说,GC 不会清理堆栈。但是,堆栈使用的空间在展开期间被回收。因此,当堆栈被弹出时,堆栈指针被“向后”移动,因此可以重用空间。

        堆栈空间不足将引发 StackOverflowException。这通常是由于无限递归的编程错误。

        【讨论】:

          【解决方案5】:

          如果不太了解 .NET 的内部结构,我会说如果您有堆栈泄漏,您将有一个崩溃的程序,因为函数/方法返回地址也存储在堆栈中(很可能无论如何)。

          如果您的堆栈以某种方式未对齐,您将遇到比内存泄漏更大的问题。

          通常方法参数和返回值存储在堆栈中(如果未优化为通过 cpu 寄存器发送)。

          【讨论】:

            【解决方案6】:

            不,只要您使用安全代码,堆栈变量就不会发生内存泄漏。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-12-02
              • 1970-01-01
              • 2011-02-10
              • 1970-01-01
              • 2012-08-19
              • 1970-01-01
              • 1970-01-01
              • 2019-08-28
              相关资源
              最近更新 更多