在采访中,采访者问我以下内容:
假设Gen 0的大小为5 kb,而我创建的对象大小为20 kb,会发生什么?
我回答说CLR将扩展Gen 0区域。
现在我很困惑这是否是正确的答案。
这是对的吗?
答案 0 :(得分:1)
具体细节取决于实现,框架版本之间可能略有不同。 Gen0和Gen1不是为了生长,而Gen2可以无限增长。突破Gen0和1的限制通常会触发一个集合。
第1代和第0代存在于称为短暂片段(每个堆中的第一个小对象片段)的东西中,并且第1代和第0代的大小永远不会超过片段的大小。如果创建了将成为新的短暂段的新段。另一方面,Gen 2可以无限增长(或直到你的内存耗尽),所以如果你的内存消耗很高,你的大量对象将会存在于Gen 2中。
根据我对大型ETL过程的经验,大型数据对象往往很快就被分配到Gen2,而Gen2垃圾收集相对不频繁,因此这些对象可以保留一段时间。
文章How does the GC work and what are the sizes of the different generations?概述了这一点以及一些相关链接。
答案 1 :(得分:1)
你最终会得到25K的第0代,除非发生一些疯狂的事情(比如另一个线程分配一堆内存或者因为其他几代人太大而触发GC)。
Gen 0的预算通常远大于25k(默认为256K),因此分配该金额不会做任何特别的事情。对象本身不大于85K,因此它也不会在大对象堆中结束。
数字(5K和20K)有点奇怪,因为它们不会接近任何有趣事件的阈值。
答案 2 :(得分:0)
LOH不等于第2代
大于85K的大多数对象将直接分配给LOH
但是第2代对象可以很小,它只能在第0代和第1代中存活,而且代数也很紧凑。
答案 3 :(得分:0)
我认为Generations中只保存了对象指针,因此无论对象大小有多大,该物理空间的地址都会很小。
答案 4 :(得分:0)
GC在Gen0,Gen1和Gen2代中工作。除此之外,还有LOH用于存储大于85kB的物体。
基于这些,如果创建了新对象,如果有足够的预算,它应该输入Gen0。如果没有足够的预算,GC将开始收集。根据Gen0的预算,Gen1和Gen2 GC还将决定运行哪一代产品。在收集期间,将丢弃未引用的对象,并将引用的对象提升为下一代。 GC的目的是尽可能保持Gen0的大小,因为Gen0集合是最常用的,但在某些情况下GC可能会尝试为Gen0分配更多的内存。
让我们假设Gen 0的大小是5 kb,而我的对象是 创造大小20 kb,会发生什么?
假设5kB是Gen0 GC的空闲内存将开始收集并尝试释放超过20kB(如果可能的话)。如果GC无法回收足够的内存,它将尝试增加Gen0并进行一些收集以回收足够的内存。即使这样,也没有足够的内存OutOfMemoryException
将被抛出。
答案 5 :(得分:-2)
大型物体将跳过第0代和第1代。
将小型.NET对象分配到Small Object Heaps(SOH)上。
...
大于85 KB的对象被分配到大对象堆(LOH)上。由于复制大块内存的开销,它们不会被压缩。当发生完整的GC时,未使用的LOH对象的地址范围将被记录在可用空间分配表中。
Source: red-gate article on .NET memory management
新分配的对象形成新一代对象,并且隐式生成0集合,除非它们是大对象,在这种情况下它们会在第2代集合中的大对象堆上进行。