Ken*_*nky 6 .net clr garbage-collection
我在.Net中遇到了一些关于垃圾收集的奇怪行为.
以下程序将非常快速地抛出OutOfMemoryException(在32位,2GB机器上不到一秒钟之后).永远不会调用Foo终结器.
class Foo
{
Guid guid = Guid.NewGuid();
byte[] buffer = new byte[1000000];
static Random rand = new Random();
public Foo()
{
// Uncomment the following line and the program will run forever.
// rand.NextBytes(buffer);
}
~Foo()
{
// This finalizer is never called unless the rand.NextBytes
// line in the constructor is uncommented.
}
static public void Main(string args[])
{
for (; ; )
{
new Foo();
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果取消注释rand.nextBytes行,它将无限运行,并定期调用Foo终结器.这是为什么?
我最好的猜测是,在前一种情况下,CLR或Windows VMM都懒得分配物理内存.永远不会写入缓冲区,因此永远不会使用物理内存.当地址空间用完时,系统崩溃.在后一种情况下,系统在用完地址空间之前耗尽物理内存,触发GC并收集对象.
但是,这是我没有得到的部分.假设我的理论是正确的,为什么地址空间不足时GC不会触发?如果我的理论不正确,那么真正的解释是什么呢?
代码在我的机器上以稳定的 18MB 运行,无论是否有该行(XP SP3 x86、.Net 3.5 SP1、双核)。
您的机器上可能发生的情况是,当对该行进行注释时,程序将大部分时间都花在分配上,并在垃圾收集器线程有机会释放它之前设法分配了太多内存。当您取消注释该行时,程序花费的分配时间会少得多,因此在 GC 线程运行之前不能分配太多时间。
尝试将注释行替换为Thread.Sleep(0); 如果它没有崩溃,我可能是对的。
顺便说一句,您不应该依赖终结器 - 它不能保证在对象被 GC 时立即被调用,甚至根本不被调用。相反,在实际代码中实现接口,并且仅在调用极其重要的IDisposable情况下才使用终结器,即使程序员忘记了它(例如释放共享网络/文件资源等)Dispose()
| 归档时间: |
|
| 查看次数: |
401 次 |
| 最近记录: |