Emb*_*rja 21 c# struct garbage-collection
我有点困惑的是,在C#中只有引用类型被垃圾收集.这意味着GC只选择内存解除分配的引用类型.那么值类型会发生什么呢?因为它们也会占用堆栈上的内存?
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分配它,因此它负责清理它.
那么值类型会发生什么呢?因为它们也会占用堆栈上的内存?
什么都没发生在他们身上.没有什么需要发生在他们身上.堆栈是一百万字节.堆栈的大小是在线程启动时确定的; 它从一百万字节开始,并且在整个线程执行期间保持一百万字节.堆栈中的内存既不会被创建也不会被破坏; 只是它的内容被改变了.
此问题中使用的动词太多,如已销毁,已回收,已取消分配,已删除.这与实际发生的情况不符.一个局部变量根本不再是挪威鹦鹉风格.
一个方法有一个单一的入口点,首先发生的是调整CPU堆栈指针.创建"堆栈框架",为局部变量创建存储空间.CLR保证将此空间初始化为0,而不是由于明确的赋值规则而在C#中强烈使用的功能.
即使您的方法代码中包含多个return语句,方法也只有一个退出点.此时,堆栈指针简单地恢复到其原始值.实际上它"忘记"了那里的局部变量.它们的值不以任何方式"擦除",字节仍然存在.但它们不会持续很长时间,程序中的下一个调用将再次覆盖它们.CLR零初始化规则确保您永远不会观察那些不安全的旧值.
非常非常快,只需一个处理器周期.C#语言中此行为的可见副作用是值类型不能具有终结器.确保不必进行额外的工作.