琦谓 发表于 2025-5-29 16:35:12

.NET陷阱之五:奇怪的OutOfMemoryException——大对象堆引起的问题与对策

我们在开发过程中曾经遇到过一个奇怪的问题:当软件加载了很多比较大规模的数据后,会偶尔出现OutOfMemoryException异常,但通过内存检查工具却发现还有很多可用内存。于是我们怀疑是可用内存总量充足,但却没有足够的连续内存了——也就是说存在很多未分配的内存空隙。但不是说.NET运行时的垃圾收集器会压缩使用中的内存,从而使已经释放的内存空隙连成一片吗?于是我深入研究了一下垃圾回收相关的内容,最终明确的了问题所在——大对象堆(LOH)的使用。如果你也遇到过类似的问题或者对相关的细节有兴趣的话,就继续读读吧。
如果没有特殊说明,后面的叙述都是针对32位系统。
首先我们来探讨另外一个问题:不考虑非托管内存的使用,在最坏情况下,当系统出现OutOfMemoryException异常时,有效的内存(程序中有GC Root的对象所占用的内存)使用量会是多大呢?2G? 1G? 500M? 50M?或者更小(是不是以为我在开玩笑)?来看下面这段代码(参考 https://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/)。
1 public class Program
2 {
3   static void Main(string[] args)
4   {
5         var smallBlockSize = 90000;
6         var largeBlockSize = 1 << 24;
7         var count = 0;
8         var bigBlock = new byte;
9         try
10         {
11             var smallBlocks = new List<byte[]>();
12             while (true)
13             {
14               GC.Collect();
15               bigBlock = new byte;
16               largeBlockSize++;
17               smallBlocks.Add(new byte);
18               count++;
19             }
20         }
21         catch (OutOfMemoryException)
22         {
23             bigBlock = null;
24             GC.Collect();
25             Console.WriteLine("{0} Mb allocated",
26               (count * smallBlockSize) / (1024 * 1024));
27         }
28         
29         Console.ReadLine();
30   }
31 } 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: .NET陷阱之五:奇怪的OutOfMemoryException——大对象堆引起的问题与对策