.NET Garbage Collection Concepts

.NET Framework的垃圾回收机制通过快速分配内存并高效回收不再使用的对象来提高应用程序性能。它利用了内存分配、代际垃圾回收等技术,并针对不同大小的对象进行优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

.NET Garbage Collection Concepts
From: http://blogs.subfuzion.org/
Memory allocation

.NET allocates memory faster than the standard C runtime malloc and Windows HeapAlloc functions. In fact, allocating memory is about as fast allocating memory from the thread’s stack. There is no traversal of a linked list to find a block of memory large enough to satisfy a memory request. Instead, an internal pointer is simply advanced to point to the next place in the private managed heap where a future memory request will be satisfied.

This feature actually provides a second major benefit: locality of reference, meaning that objects allocated around the same time will be physically proximate. So in addition to faster allocation, there is improved runtime performance because of drastically better cpu cache performance (avoiding slower RAM access) and far fewer page faults.

There is a further optimization that large objects (>20K) are allocated from a special heap. See Richter’s articles (below) for more details.

Of course, unless a program’s memory requirements are extremely modest, sooner or later a request for memory will fail. That is when the garbage collector will be invoked. Let me repeat this another way since there is a misconception that having a garbage collector means a background thread is waking up periodically to do some housekeeping: there is no garbage collector “heartbeat” – nothing running in the background on some schedule. The garbage collector runs when it becomes necessary to reclaim memory to satisfy new memory request.

Where some people might get confused is that a separate thread will peform special “finalization” of objects that implement a finalize method, but only after the collector has marked them for collection and added them to a special internal queue. A special thread is awakened when objects are placed on this queue so that their finalize method can be executed. Therefore, this thread only runs after a garbage collection cycle places objects with finalizers in this special queue, and garbage collection only happened because a memory request could not be satisfied in the first place.

Generational garbage collection

As already discussed, the garbage collector doesn’t run until a request for memory (new) fails. At that point, the collector begins to look for candidates to reclaim. Conceptually this is very simple: if objects on the heap have nothing pointing to them (because references to them went out of scope or were set to null), then they are garbage and can be reclaimed.

The .NET implemenation of checking for garbage is heavily optimized and happens very quickly. The garbage collector does not generally need to scan every object on the heap. It maintains three separate graphs of objects representing generations. Initially, there is only generation 0. The first time the collector makes a collection pass, objects that survive are promoted to generation 1. Survivors of subsequent passes are promoted to generation 2. The principle is simple. Long lived objects don’t need to be checked as frequently since they are, well, long-lived. If they are garbage collection survivors, then subsequent passes won’t waste time looking at them unless memory is getting so low that a pass through one generation didn’t reclaim enough.

Microsoft invested a great deal of effort in ensuring that the .NET garbage collector performed as optimally as possible. As Richter points out, the performance six years ago was already impressive:

Microsoft's performance tests show that managed heap allocations are faster than standard allocations performed by the Win32 HeapAlloc function. These tests also show that it takes less than 1 millisecond on a 200Mhz Pentium to perform a full GC of generation 0. It is Microsoft's goal to make GCs take no more time than an ordinary page fault.

Many people don’t realize that the net result is that the penalty for memory management in unmanaged code can actually be greater than for managed, garbage-collected code. One argument for manual memory management is that the penalty for manually freeing memory is more deterministic than garbage collection. Ironically, manually allocating memory is actually less deterministic (for standard memory allocators, such as provided by the standard C runtime library).

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值