好的,所以我了解堆栈和堆(值存在于堆栈中,引用位于堆中)。
当我声明一个Class的新实例时,它存在于堆中,并引用了堆栈中内存中的这一点。我也知道C#自己做垃圾收集(即,它确定何时不再使用实例化的类并回收内存)。
我有两个问题:
我问是因为我在For循环中有一个方法。每次循环时,我都会创建一个新的Class实例。在我的脑海中,我将所有这些类想象成堆,而不是做任何事情,而是占用内存,我想尽快消除它们,以使事情保持整洁!
我是否正确理解这一点,或者我缺少什么?
最佳答案
我认为您不了解堆栈和堆。如果值在堆栈上,那么整数数组在哪里?整数是值。您是在告诉我整数数组将其整数保留在堆栈中吗?当您从某个方法返回一个整数数组(例如其中包含一万个整数)时,您是否告诉我那一万个整数已复制到堆栈上?
值在堆栈中时,它们就在堆栈中,而当它们在堆中时,它们就在堆中。事物的类型与它的存储生命周期有关的想法是胡说八道。生命周期短的存储位置放在堆栈上;生命周期长的存储位置在堆上,并且与它们的类型无关。生命周期很长的int必须放在堆上,与类的生命周期很长的实例相同。
为什么引用必须放在堆栈上?同样,引用的存储生命周期与它的类型无关。如果引用的存储空间很长,那么该引用将进入堆。
C#语言不会这样做; CLR这样做。
您似乎相信很多关于堆栈和堆的谎言,所以赔率不错,不是,不是。
不是在C#中,不是。
垃圾收集的全部目的是使您不必担心整理。这就是为什么将其称为“自动垃圾收集”。它为您整理。
如果您担心循环会产生收集压力,并且出于性能原因希望避免收集压力,那么建议您采用池化策略。从一个明确的合并策略开始是明智的。那是:
while(whatever)
{
Frob f = FrobPool.FetchFromPool();
f.Blah();
FrobPool.ReturnToPool(f);
}
而不是尝试使用复活的终结器进行自动池化。我一般建议不要同时使用终结器和对象复活,除非您是终结语义专家。
如果池中没有一个Frob,则该池当然会分配一个新的Frob。如果池中有一个池,则它将它递出并从池中移出,直到放回池中。(如果您忘记将Frob放回池中,则GC最终会到达池中。)一种池化策略会导致GC最终将所有Frobs移至第二代堆,而不是在第0代堆中创建大量收集压力。由于没有分配新的Frob,收集压力便消失了。如果其他原因产生了收集压力,则将Frobs安全地放在第2代堆中,很少有人造访。
当然,这与您描述的策略完全相反。池化策略的全部目的是使对象永远卡在身边。如果您要使用对象,那么永远挂着的对象是一件好事。
当然,在通过概要分析得知由于收集压力而导致性能问题之前,请不要进行此类更改!在台式机CLR上很少有这种问题。它在紧凑型CLR上更为常见。
更一般地说,如果您是那种不愿意让内存管理器按计划为您清理的人,那么C#不是您的正确语言。考虑使用C。
关于c# - C#-垃圾回收,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8730451/