在C#中销毁一个struct对象?

Emb*_*rja 21 c# struct garbage-collection

我有点困惑的是,在C#中只有引用类型被垃圾收集.这意味着GC只选择内存解除分配的引用类型.那么值类型会发生什么呢?因为它们也会占用堆栈上的内存?

Jon*_*eet 31

首先,它们是在堆栈还是堆的一部分取决于它们所属的上下文 - 如果它们在引用类型中,它们无论如何都会在堆上.(无论如何,你应该考虑你真正关心堆栈/堆分裂的程度 - 正如Eric Lippert写的那样,它主要是一个实现细节.)

但是,回收上下文时基本上会回收值类型内存 - 因此当您从方法返回时弹出堆栈时,"回收"整个堆栈帧.同样,如果值类型值实际上是对象的一部分,则在该对象被垃圾回收时回收内存.

简短的回答是你不必担心它:)(这假设除了内存之外你没有其他任何事情要担心,当然 - 如果你有结构引用需要释放的本机句柄,这是一个有点不同的情况.)


Eri*_*ert 19

我有点困惑的是,在C#中只有引用类型被垃圾收集.

这不是事实.或者说,这个陈述的真实性或虚假性取决于你"收集垃圾"的意思.垃圾收集器在收集时肯定会查看值类型; 这些值类型可能存在并保持引用类型:

struct S { public string str; }
...
S s = default(S); // local variable of value type
s.str = M(); 
Run Code Online (Sandbox Code Playgroud)

当垃圾收集器运行时,它肯定会查看s,因为它需要确定s.str仍然存活.

我的建议:用动词"收集垃圾"来准确澄清你的意思.

GC仅选择内存解除分配的引用类型.

同样,这不是事实.假设你有一个实例

class C { int x; }
Run Code Online (Sandbox Code Playgroud)

整数的内存将位于垃圾收集堆上,因此当C实例无根时由垃圾收集器回收.

为什么你会相信垃圾收集器只释放引用类型的内存?正确的说法是由垃圾收集器分配的内存由垃圾收集器释放,我认为这是完全合理的.GC分配它,因此它负责清理它.

那么值类型会发生什么呢?因为它们也会占用堆栈上的内存?

什么都没发生在他们身上.没有什么需要发生在他们身上.堆栈是一百万字节.堆栈的大小是在线程启动时确定的; 它从一百万字节开始,并且在整个线程执行期间保持一百万字节.堆栈中的内存既不会被创建也不会被破坏; 只是它的内容被改变了.

  • "堆栈中的内存既不会被创建也不会被破坏" - 我建议我们称之为[Stack]内存保存的Lippert定律**.:) (28认同)

Han*_*ant 7

此问题中使用的动词太多,如已销毁,已回收,已取消分配,已删除.这与实际发生的情况不符.一个局部变量根本不再是挪威鹦鹉风格.

一个方法有一个单一的入口点,首先发生的是调整CPU堆栈指针.创建"堆栈框架",为局部变量创建存储空间.CLR保证将此空间初始化为0,而不是由于明确的赋值规则而在C#中强烈使用的功能.

即使您的方法代码中包含多个return语句,方法也只有一个退出点.此时,堆栈指针简单地恢复到其原始值.实际上它"忘记"了那里的局部变量.它们的值不以任何方式"擦除",字节仍然存在.但它们不会持续很长时间,程序中的下一个调用将再次覆盖它们.CLR零初始化规则确保您永远不会观察那些不安全的旧值.

非常非常快,只需一个处理器周期.C#语言中此行为的可见副作用是值类型不能具有终结器.确保不必进行额外的工作.