当前位置: 首页 > 编程语言 > C#

C#学习教程:.NET垃圾收集器的奥秘分享

时间:2023-04-10 16:31:47 C#

.NET垃圾收集器之谜在我的工作中,我们遇到了OutOfMemoryExceptions问题。我写了一段简单的代码来模仿一些行为,最后我遇到了以下谜团。看看这段内存耗尽时会爆炸的简单代码。类程序{privatestaticvoidMain(){Listlist=newList(200000);整数迭代器=0;尝试{for(;;iter++){list.Add(newbyte[10000]);}}catch(OutOfMemoryException){Console.WriteLine("Iterations:"+iter);在我的机器上它结束Iterations:148008然后我在每千次迭代后添加一个GC.Collect调用循环://...for(;;iter++){list.Add(newbyte[10000]);如果(iter%1000==0)GC.Collect();}//...惊喜:Iterations:172048当我在每10次CallingGC.Collect迭代后得到时,我什至得到了193716个循环。两件奇怪的事情:手动调用GC.Collect怎么会产生如此严重的影响(分配高达30%)?在没有引用“丢失”的情况下(我什至预设了List的容量),GC能收集什么?垃圾收集过程的一部分是压缩阶段。在此阶段,移动分配的内存块以减少排序。分配内存时,并不总是在最后一块分配的内存中断后立即分配。因此,当垃圾收集器通过更好地利用可用空间来腾出更多空间时,您可以进一步挤压。我正在尝试运行一些测试,但我的机器无法处理它们。试试看,它会告诉GC将对象固定在内存中,这样它们就不会被移动byte[]b=newbyte[10000];GCHandle.Alloc(b,GCHandleType.Pinned);列表.添加(b);至于你的评论,当GC移动时,它不会擦除任何东西,它只是更好地利用所有内存空间。让我们尝试简化它。当你第一次分配你的字节数组时,假设它从点0到10000插入内存??。下次你分配一个字节数组时,它不能保证从10001开始,它可能从10500开始。所以现在你有499个未使用的字节,并且您的应用程序不会使用它。因此,当GC压缩时,它将10500arrays移动到10001以便能够使用额外的499字节。同样,这是简化的方法。根据您使用的CLR,可能会涉及一些大对象堆问题。看看这篇文章,它解释了块分配的问题(一个包含200000项的列表肯定是一个块,另一个可能是也可能不是,它似乎在某些数组达到8k时放入LOH,其他85k之后人们)。http://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/CLR偶尔会将数组放在LOH上。如果您通过WinDbg查看内存转储,您会发现有些数组小于85,000字节。这是未记录的行为-但这就是它的工作原理。您收到OutOfMemoryErrors是因为您正在拆分LOH堆并且LOH堆从未被压缩。关于你的问题:2)当没有引用“丢失”(我什至预设了List的容量)时,GC可以收集什么?您传递的新byte[10000]会覆盖要添加到列表中的引用。编译局部变量并将其分配给newbyte[10000]。对于循环中的每次迭代,您都会创建一个预定义大小为10000的新byte[]并将其分配给局部变量。该变量的任何先前值都将被覆盖,并且该内存将有资格在下次GC运行以生成该变量时进行收集(在这种情况下,可能是LOH)。我在.NET中遇到了类似的问题,我的byte[]具有随机大小。我尝试了两种方法:如果可能,您可以尝试.NET4.5http://blogs.msdn.com/b/dotnet/archive/2012/07/20/the-net-framework-4-5-includes-new-garbage-collector-enhancements-forclientandserver,apps.aspx以上就是C#学习教程的全部内容:.NET垃圾收集器的奥秘,如果对大家有用还需要进一步了解C#的学习教程,希望大家多多关注——本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: