垃圾回收的基本知识Fundamentals of garbage collection

在公共语言运行时 (CLR) 中,垃圾回收器 (GC) 用作自动内存管理器。In the common language runtime (CLR), the garbage collector (GC) serves as an automatic memory manager. 垃圾回收器管理应用程序的内存分配和释放。The garbage collector manages the allocation and release of memory for an application. 对于使用托管代码的开发人员而言,这就意味着不必编写执行内存管理任务的代码。For developers working with managed code, this means that you don't have to write code to perform memory management tasks. 自动内存管理可解决常见问题,例如,忘记释放对象并导致内存泄漏,或尝试访问已释放对象的内存。Automatic memory management can eliminate common problems, such as forgetting to free an object and causing a memory leak or attempting to access memory for an object that's already been freed.

本文章介绍垃圾回收的核心概念。This article describes the core concepts of garbage collection.

优点Benefits

垃圾回收器具有以下优点:The garbage collector provides the following benefits:

  • 开发人员不必手动释放内存。Frees developers from having to manually release memory.

  • 有效分配托管堆上的对象。Allocates objects on the managed heap efficiently.

  • 回收不再使用的对象,清除它们的内存,并保留内存以用于将来分配。Reclaims objects that are no longer being used, clears their memory, and keeps the memory available for future allocations. 托管对象会自动获取干净的内容来开始,因此,它们的构造函数不必对每个数据字段进行初始化。Managed objects automatically get clean content to start with, so their constructors don't have to initialize every data field.

  • 通过确保对象不能使用另一个对象的内容来提供内存安全。Provides memory safety by making sure that an object cannot use the content of another object.

内存基础知识Fundamentals of memory

下面的列表总结了重要的 CLR 内存概念。The following list summarizes important CLR memory concepts.

  • 每个进程都有其自己单独的虚拟地址空间。Each process has its own, separate virtual address space. 同一台计算机上的所有进程共享相同的物理内存和页文件(如果有)。All processes on the same computer share the same physical memory and the page file, if there is one.

  • 默认情况下,32 位计算机上的每个进程都具有 2 GB 的用户模式虚拟地址空间。By default, on 32-bit computers, each process has a 2-GB user-mode virtual address space.

  • 作为一名应用程序开发人员,你只能使用虚拟地址空间,请勿直接操控物理内存。As an application developer, you work only with virtual address space and never manipulate physical memory directly. 垃圾回收器为你分配和释放托管堆上的虚拟内存。The garbage collector allocates and frees virtual memory for you on the managed heap.

    如果你编写的是本机代码,请使用 Windows 函数处理虚拟地址空间。If you're writing native code, you use Windows functions to work with the virtual address space. 这些函数为你分配和释放本机堆上的虚拟内存。These functions allocate and free virtual memory for you on native heaps.

  • 虚拟内存有三种状态:Virtual memory can be in three states:

    状态State 描述Description
    FreeFree 该内存块没有引用关系,可用于分配。The block of memory has no references to it and is available for allocation.
    保留Reserved 内存块可供你使用,并且不能用于任何其他分配请求。The block of memory is available for your use and cannot be used for any other allocation request. 但是,在该内存块提交之前,你无法将数据存储到其中。However, you cannot store data to this memory block until it is committed.
    已提交Committed 内存块已指派给物理存储。The block of memory is assigned to physical storage.
  • 可能会存在虚拟地址空间碎片。Virtual address space can get fragmented. 就是说地址空间中存在一些被称为孔的可用块。This means that there are free blocks, also known as holes, in the address space. 当请求虚拟内存分配时,虚拟内存管理器必须找到满足该分配请求的足够大的单个可用块。When a virtual memory allocation is requested, the virtual memory manager has to find a single free block that is large enough to satisfy that allocation request. 即使有 2 GB 可用空间,2 GB 分配请求也会失败,除非所有这些可用空间都位于一个地址块中。Even if you have 2 GB of free space, an allocation that requires 2 GB will be unsuccessful unless all of that free space is in a single address block.

  • 如果没有足够的可供保留的虚拟地址空间或可供提交的物理空间,则可能会用尽内存。You can run out of memory if there isn't enough virtual address space to reserve or physical space to commit.

    即使在物理内存压力(即物理内存的需求)较低的情况下也会使用页文件。The page file is used even if physical memory pressure (that is, demand for physical memory) is low. 首次出现物理内存压力较高的情况时,操作系统必须在物理内存中腾出空间来存储数据,并将物理内存中的部分数据备份到页文件中。The first time that physical memory pressure is high, the operating system must make room in physical memory to store data, and it backs up some of the data that is in physical memory to the page file. 该数据只会在需要时进行分页,所以在物理内存压力较低的情况下也可能会进行分页。That data is not paged until it's needed, so it's possible to encounter paging in situations where the physical memory pressure is low.

内存分配Memory allocation

初始化新进程时,运行时会为进程保留一个连续的地址空间区域。When you initialize a new process, the runtime reserves a contiguous region of address space for the process. 这个保留的地址空间被称为托管堆。This reserved address space is called the managed heap. 托管堆维护着一个指针,用它指向将在堆中分配的下一个对象的地址。The managed heap maintains a pointer to the address where the next object in the heap will be allocated. 最初,该指针设置为指向托管堆的基址。Initially, this pointer is set to the managed heap's base address. 托管堆上部署了所有引用类型。All reference types are allocated on the managed heap. 应用程序创建第一个引用类型时,将为托管堆的基址中的类型分配内存。When an application creates the first reference type, memory is allocated for the type at the base address of the managed heap. 应用程序创建下一个对象时,垃圾回收器在紧接第一个对象后面的地址空间内为它分配内存。When the application creates the next object, the garbage collector allocates memory for it in the address space immediately following the first object. 只要地址空间可用,垃圾回收器就会继续以这种方式为新对象分配空间。As long as address space is available, the garbage collector continues to allocate space for new objects in this manner.

从托管堆中分配内存要比非托管内存分配速度快。Allocating memory from the managed heap is faster than unmanaged memory allocation. 由于运行时通过为指针添加值来为对象分配内存,所以这几乎和从堆栈中分配内存一样快。Because the runtime allocates memory for an object by adding a value to a pointer, it's almost as fast as allocating memory from the stack. 另外,由于连续分配的新对象在托管堆中是连续存储,所以应用程序可以快速访问这些对象。In addition, because new objects that are allocated consecutively are stored contiguously in the managed heap, an application can access the objects quickly.

内存释放Memory release

垃圾回收器的优化引擎根据所执行的分配决定执行回收的最佳时间。The garbage collector's optimizing engine determines the best time to perform a collection based on the allocations being made. 垃圾回收器在执行回收时,会释放应用程序不再使用的对象的内存。When the garbage collector performs a collection, it releases the memory for objects that are no longer being used by the application. 它通过检查应用程序的根来确定不再使用的对象。It determines which objects are no longer being used by examining the application's roots. 应用程序的根包含线程堆栈上的静态字段、局部变量和参数以及 CPU 寄存器。An application's roots include static fields, local variables and parameters on a thread's stack, and CPU registers. 每个根或者引用托管堆中的对象,或者设置为空。Each root either refers to an object on the managed heap or is set to null. 垃圾回收器可以访问由实时 (JIT) 编译器和运行时维护的活动根的列表。The garbage collector has access to the list of active roots that the just-in-time (JIT) compiler and the runtime maintain. 垃圾回收器使用此列表创建一个图表,其中包含所有可从这些根中访问的对象。Using this list, the garbage collector creates a graph that contains all the objects that are reachable from the roots.

不在该图表中的对象将无法从应用程序的根中访问。Objects that are not in the graph are unreachable from the application's roots. 垃圾回收器会考虑无法访问的对象垃圾,并释放为它们分配的内存。The garbage collector considers unreachable objects garbage and releases the memory allocated for them. 在回收中,垃圾回收器检查托管堆,查找无法访问对象所占据的地址空间块。During a collection, the garbage collector examines the managed heap, looking for the blocks of address space occupied by unreachable objects. 发现无法访问的对象时,它就使用内存复制功能来压缩内存中可以访问的对象,释放分配给不可访问对象的地址空间块。As it discovers each unreachable object, it uses a memory-copying function to compact the reachable objects in memory, freeing up the blocks of address spaces allocated to unreachable objects. 在压缩了可访问对象的内存后,垃圾回收器就会做出必要的指针更正,以便应用程序的根指向新地址中的对象。Once the memory for the reachable objects has been compacted, the garbage collector makes the necessary pointer corrections so that the application's roots point to the objects in their new locations. 它还将托管堆指针定位至最后一个可访问对象之后。It also positions the managed heap's pointer after the last reachable object.

只有在回收发现大量的无法访问的对象时,才会压缩内存。Memory is compacted only if a collection discovers a significant number of unreachable objects. 如果托管堆中的所有对象均未被回收,则不需要压缩内存。If all the objects in the managed heap survive a collection, then there is no need for memory compaction.

为了改进性能,运行时为单独堆中的大型对象分配内存。To improve performance, the runtime allocates memory for large objects in a separate heap. 垃圾回收器会自动释放大型对象的内存。The garbage collector automatically releases the memory for large objects. 但是,为了避免移动内存中的大型对象,通常不会压缩此内存。However, to avoid moving large objects in memory, this memory is usually not compacted.

垃圾回收的条件Conditions for a garbage collection

当满足以下条件之一时将发生垃圾回收:Garbage collection occurs when one of the following conditions is true:

  • 系统具有低的物理内存。The system has low physical memory. 这是通过 OS 的内存不足通知或主机指示的内存不足检测出来。This is detected by either the low memory notification from the OS or low memory as indicated by the host.

  • 由托管堆上已分配的对象使用的内存超出了可接受的阈值。The memory that's used by allocated objects on the managed heap surpasses an acceptable threshold. 随着进程的运行,此阈值会不断地进行调整。This threshold is continuously adjusted as the process runs.

  • 调用 GC.Collect 方法。The GC.Collect method is called. 几乎在所有情况下,你都不必调用此方法,因为垃圾回收器会持续运行。In almost all cases, you don't have to call this method, because the garbage collector runs continuously. 此方法主要用于特殊情况和测试。This method is primarily used for unique situations and testing.

托管堆The managed heap

在垃圾回收器由 CLR 初始化之后,它会分配一段内存用于存储和管理对象。After the garbage collector is initialized by the CLR, it allocates a segment of memory to store and manage objects. 此内存称为托管堆(与操作系统中的本机堆相对)。This memory is called the managed heap, as opposed to a native heap in the operating system.

每个托管进程都有一个托管堆。There is a managed heap for each managed process. 进程中的所有线程都在同一堆上为对象分配内存。All threads in the process allocate memory for objects on the same heap.

若要保留内存,垃圾回收器会调用 Windows VirtualAlloc 函数,并且每次为托管应用保留一个内存段。To reserve memory, the garbage collector calls the Windows VirtualAlloc function and reserves one segment of memory at a time for managed applications. 垃圾回收器还会根据需要保留内存段,并调用 Windows VirtualFree 函数,将内存段释放回操作系统(在清除所有对象的内存段后)。The garbage collector also reserves segments, as needed, and releases segments back to the operating system (after clearing them of any objects) by calling the Windows VirtualFree function.

重要

垃圾回收器分配的段大小特定于实现,并且随时可能更改(包括定期更新)。The size of segments allocated by the garbage collector is implementation-specific and is subject to change at any time, including in periodic updates. 应用程序不应假设特定段的大小或依赖于此大小,也不应尝试配置段分配可用的内存量。Your app should never make assumptions about or depend on a particular segment size, nor should it attempt to configure the amount of memory available for segment allocations.

堆上分配的对象越少,垃圾回收器必须执行的工作就越少。The fewer objects allocated on the heap, the less work the garbage collector has to do. 分配对象时,请勿使用超出你需求的舍入值,例如在仅需要 15 个字节的情况下分配了 32 个字节的数组。When you allocate objects, don't use rounded-up values that exceed your needs, such as allocating an array of 32 bytes when you need only 15 bytes.

当触发垃圾回收时,垃圾回收器将回收由非活动对象占用的内存。When a garbage collection is triggered, the garbage collector reclaims the memory that's occupied by dead objects. 回收进程会对活动对象进行压缩,以便将它们一起移动,并移除死空间,从而使堆更小一些。The reclaiming process compacts live objects so that they are moved together, and the dead space is removed, thereby making the heap smaller. 这将确保一起分配的对象全都位于托管堆上,从而保留它们的局部性。This ensures that objects that are allocated together stay together on the managed heap to preserve their locality.

垃圾回收的侵入性(频率和持续时间)是由分配的数量和托管堆上保留的内存数量决定的。The intrusiveness (frequency and duration) of garbage collections is the result of the volume of allocations and the amount of survived memory on the managed heap.

此堆可视为两个堆的累计:大对象堆和小对象堆。The heap can be considered as the accumulation of two heaps: the large object heap and the small object heap. 大对象堆包含大小为 85,000 个字节和更多字节的对象,这些对象通常是数组。The large object heap contains objects that are 85,000 bytes and larger, which are usually arrays. 非常大的实例对象是很少见的。It's rare for an instance object to be extremely large.

提示

可以配置阈值大小,以使对象能够进入大型对象堆。You can configure the threshold size for objects to go on the large object heap.

代数Generations

GC 算法基于几个注意事项:The GC algorithm is based on several considerations:

  • 压缩托管堆的一部分内存要比压缩整个托管堆速度快。It's faster to compact the memory for a portion of the managed heap than for the entire managed heap.
  • 较新的对象生存期较短,而较旧的对象生存期则较长。Newer objects have shorter lifetimes and older objects have longer lifetimes.
  • 较新的对象趋向于相互关联,并且大致同时由应用程序访问。Newer objects tend to be related to each other and accessed by the application around the same time.

垃圾回收主要在回收短生存期对象时发生。Garbage collection primarily occurs with the reclamation of short-lived objects. 为优化垃圾回收器的性能,将托管堆分为三代:第 0 代、第 1 代和第 2 代,因此它可以单独处理长生存期和短生存期对象。To optimize the performance of the garbage collector, the managed heap is divided into three generations, 0, 1, and 2, so it can handle long-lived and short-lived objects separately. 垃圾回收器将新对象存储在第 0 代中。The garbage collector stores new objects in generation 0. 在应用程序生存期的早期创建的对象如果未被回收,则被升级并存储在第 1 级和第 2 级中。Objects created early in the application's lifetime that survive collections are promoted and stored in generations 1 and 2. 因为压缩托管堆的一部分要比压缩整个托管堆速度快,所以此方案允许垃圾回收器在每次执行回收时释放特定级别的内存,而不是整个托管堆的内存。Because it's faster to compact a portion of the managed heap than the entire heap, this scheme allows the garbage collector to release the memory in a specific generation rather than release the memory for the entire managed heap each time it performs a collection.

  • 第 0 代Generation 0. 这是最年轻的代,其中包含短生存期对象。This is the youngest generation and contains short-lived objects. 短生存期对象的一个示例是临时变量。An example of a short-lived object is a temporary variable. 垃圾回收最常发生在此代中。Garbage collection occurs most frequently in this generation.

    新分配的对象构成新一代对象,并隐式地成为第 0 代集合。Newly allocated objects form a new generation of objects and are implicitly generation 0 collections. 但是,如果它们是大型对象,它们将延续到大型对象堆 (LOH),这有时称为第 3 代。However, if they are large objects, they go on the large object heap (LOH), which is sometimes referred to as generation 3. 第 3 代是在第 2 代中逻辑收集的物理生成。Generation 3 is a physical generation that's logically collected as part of generation 2.

    大多数对象通过第 0 代中的垃圾回收进行回收,不会保留到下一代。Most objects are reclaimed for garbage collection in generation 0 and don't survive to the next generation.

    如果应用程序在第 0 代托管堆已满时尝试创建新对象,垃圾回收器将执行收集,以尝试为该对象释放地址空间。If an application attempts to create a new object when generation 0 is full, the garbage collector performs a collection in an attempt to free address space for the object. 垃圾回收器从检查第 0 级托管堆中的对象(而不是托管堆中的所有对象)开始执行回收。The garbage collector starts by examining the objects in generation 0 rather than all objects in the managed heap. 单独回收第 0 代托管堆通常可以回收足够的内存,这样,应用程序便可以继续创建新对象。A collection of generation 0 alone often reclaims enough memory to enable the application to continue creating new objects.

  • 第 1 代Generation 1. 这一代包含短生存期对象并用作短生存期对象和长生存期对象之间的缓冲区。This generation contains short-lived objects and serves as a buffer between short-lived objects and long-lived objects.

    垃圾回收器执行第 0 代托管堆的回收后,会压缩可访问对象的内存,并将其升级到第 1 代。After the garbage collector performs a collection of generation 0, it compacts the memory for the reachable objects and promotes them to generation 1. 因为未被回收的对象往往具有较长的生存期,所以将它们升级至更高的级别很有意义。Because objects that survive collections tend to have longer lifetimes, it makes sense to promote them to a higher generation. 垃圾回收器在每次执行第 0 代托管堆的回收时,不必重新检查第 1 代和第 2 代托管堆中的对象。The garbage collector doesn't have to reexamine the objects in generations 1 and 2 each time it performs a collection of generation 0.

    如果第 0 代托管堆的回收没有回收足够的内存供应用程序创建新对象,垃圾回收器就会先执行第 1 代托管堆的回收,然后再执行第 2 代托管堆的回收。If a collection of generation 0 does not reclaim enough memory for the application to create a new object, the garbage collector can perform a collection of generation 1, then generation 2. 第 1 级托管堆中未被回收的对象将会升级至第 2 级托管堆。Objects in generation 1 that survive collections are promoted to generation 2.

  • 第 2 代Generation 2. 这一代包含长生存期对象。This generation contains long-lived objects. 长生存期对象的一个示例是服务器应用程序中的一个包含在进程期间处于活动状态的静态数据的对象。An example of a long-lived object is an object in a server application that contains static data that's live for the duration of the process.

    第 2 代托管堆中未被回收的对象会继续保留在第 2 代托管堆中,直到在将来的回收中确定它们无法访问为止。Objects in generation 2 that survive a collection remain in generation 2 until they are determined to be unreachable in a future collection.

    大型对象堆上的对象(有时称为 第 3 代)也在第 2 代中收集。Objects on the large object heap (which is sometimes referred to as generation 3) are also collected in generation 2.

当条件得到满足时,垃圾回收将在特定代上发生。Garbage collections occur on specific generations as conditions warrant. 回收某个代意味着回收此代中的对象及其所有更年轻的代。Collecting a generation means collecting objects in that generation and all its younger generations. 第 2 代垃圾回收也称为完整垃圾回收,因为它回收所有代中的对象(即,托管堆中的所有对象)。A generation 2 garbage collection is also known as a full garbage collection, because it reclaims objects in all generations (that is, all objects in the managed heap).

幸存和提升Survival and promotions

垃圾回收中未回收的对象也称为幸存者,并会被提升到下一代:Objects that are not reclaimed in a garbage collection are known as survivors and are promoted to the next generation:

  • 第 0 代垃圾回收中未被回收的对象将会升级至第 1 代。Objects that survive a generation 0 garbage collection are promoted to generation 1.
  • 第 1 代垃圾回收中未被回收的对象将会升级至第 2 代。Objects that survive a generation 1 garbage collection are promoted to generation 2.
  • 第 2 代垃圾回收中未被回收的对象将仍保留在第 2 代。Objects that survive a generation 2 garbage collection remain in generation 2.

当垃圾回收器检测到某个代中的幸存率很高时,它会增加该代的分配阈值。When the garbage collector detects that the survival rate is high in a generation, it increases the threshold of allocations for that generation. 下次回收将回收非常大的内存。The next collection gets a substantial size of reclaimed memory. CLR 持续在以下两个优先级之间进行平衡:不允许通过延迟垃圾回收,让应用程序的工作集获取太大内存,以及不允许垃圾回收过于频繁地运行。The CLR continually balances two priorities: not letting an application's working set get too large by delaying garbage collection and not letting the garbage collection run too frequently.

暂时代和暂时段Ephemeral generations and segments

因为第 0 代和第 1 代中的对象的生存期较短,因此,这些代被称为“暂时代”。Because objects in generations 0 and 1 are short-lived, these generations are known as the ephemeral generations.

暂时代在称为“暂时段”的内存段中进行分配。Ephemeral generations are allocated in the memory segment that's known as the ephemeral segment. 垃圾回收器获取的每个新段将成为新的暂时段,并包含在第 0 代垃圾回收中幸存的对象。Each new segment acquired by the garbage collector becomes the new ephemeral segment and contains the objects that survived a generation 0 garbage collection. 旧的暂时段将成为新的第 2 代段。The old ephemeral segment becomes the new generation 2 segment.

根据系统为 32 位还是 64 位以及它正在哪种类型的垃圾回收器(工作站或服务器 GC)上运行,暂时段的大小发生相应变化。The size of the ephemeral segment varies depending on whether a system is 32-bit or 64-bit and on the type of garbage collector it is running (workstation or server GC). 下表显示了暂时段的默认大小。The following table shows the default sizes of the ephemeral segment.

工作站/服务器 GCWorkstation/server GC 32 位32-bit 64 位64-bit
工作站 GCWorkstation GC 16 MB16 MB 256 MB256 MB
服务器 GCServer GC 64 MB64 MB 4 GB4 GB
服务器 GC(具有 4 个以上的逻辑 CPU)Server GC with > 4 logical CPUs 32 MB32 MB 2 GB2 GB
服务器 GC(具有 8 个以上的逻辑 CPU)Server GC with > 8 logical CPUs 16 MB16 MB 1 GB1 GB

暂时段可以包含第 2 代对象。The ephemeral segment can include generation 2 objects. 第 2 代对象可使用多个段(在内存允许的情况下进程所需的任意数量)。Generation 2 objects can use multiple segments (as many as your process requires and memory allows for).

从暂时垃圾回收中释放的内存量限制为暂时段的大小。The amount of freed memory from an ephemeral garbage collection is limited to the size of the ephemeral segment. 释放的内存量与死对象占用的空间成比例。The amount of memory that is freed is proportional to the space that was occupied by the dead objects.

垃圾回收过程中发生的情况What happens during a garbage collection

垃圾回收分为以下几个阶段:A garbage collection has the following phases:

  • 标记阶段,找到并创建所有活动对象的列表。A marking phase that finds and creates a list of all live objects.

  • 重定位阶段,用于更新对将要压缩的对象的引用。A relocating phase that updates the references to the objects that will be compacted.

  • 压缩阶段,用于回收由死对象占用的空间,并压缩幸存的对象。A compacting phase that reclaims the space occupied by the dead objects and compacts the surviving objects. 压缩阶段将垃圾回收中幸存下来的对象移至段中时间较早的一端。The compacting phase moves objects that have survived a garbage collection toward the older end of the segment.

    因为第 2 代回收可以占用多个段,所以可以将已提升到第 2 代中的对象移动到时间较早的段中。Because generation 2 collections can occupy multiple segments, objects that are promoted into generation 2 can be moved into an older segment. 可以将第 1 代幸存者和第 2 代幸存者都移动到不同的段,因为它们已被提升到第 2 代。Both generation 1 and generation 2 survivors can be moved to a different segment, because they are promoted to generation 2.

    通常,由于复制大型对象会造成性能代偿,因此不会压缩大型对象堆 (LOH)。Ordinarily, the large object heap (LOH) is not compacted, because copying large objects imposes a performance penalty. 但是,在 .NET Core 和 .NET Framework 4.5.1 及更高版本中,可以根据需要使用 GCSettings.LargeObjectHeapCompactionMode 属性按需压缩大型对象堆。However, in .NET Core and in .NET Framework 4.5.1 and later, you can use the GCSettings.LargeObjectHeapCompactionMode property to compact the large object heap on demand. 此外,当通过指定以下任一项设置硬限制时,将自动压缩 LOH:In addition, the LOH is automatically compacted when a hard limit is set by specifying either:

垃圾回收器使用以下信息来确定对象是否为活动对象:The garbage collector uses the following information to determine whether objects are live:

  • 堆栈根Stack roots. 由实时 (JIT) 编译器和堆栈查看器提供的堆栈变量。Stack variables provided by the just-in-time (JIT) compiler and stack walker. JIT 优化可以延长或缩短报告给垃圾回收器的堆栈变量内的代码的区域。JIT optimizations can lengthen or shorten regions of code within which stack variables are reported to the garbage collector.

  • 垃圾回收句柄Garbage collection handles. 指向托管对象且可由用户代码或公共语言运行时分配的句柄。Handles that point to managed objects and that can be allocated by user code or by the common language runtime.

  • 静态数据Static data. 应用程序域中可能引用其他对象的静态对象。Static objects in application domains that could be referencing other objects. 每个应用程序域都会跟踪其静态对象。Each application domain keeps track of its static objects.

在垃圾回收启动之前,除了触发垃圾回收的线程以外的所有托管线程均会挂起。Before a garbage collection starts, all managed threads are suspended except for the thread that triggered the garbage collection.

下图演示了触发垃圾回收并导致其他线程挂起的线程。The following illustration shows a thread that triggers a garbage collection and causes the other threads to be suspended.

线程触发垃圾回收时

非托管资源Unmanaged resources

对于应用程序创建的大多数对象,可以依赖垃圾回收自动执行必要的内存管理任务。For most of the objects that your application creates, you can rely on garbage collection to automatically perform the necessary memory management tasks. 但是,非托管资源需要显式清除。However, unmanaged resources require explicit cleanup. 最常用的非托管资源类型是包装操作系统资源的对象,例如,文件句柄、窗口句柄或网络连接。The most common type of unmanaged resource is an object that wraps an operating system resource, such as a file handle, window handle, or network connection. 虽然垃圾回收器可以跟踪封装非托管资源的托管对象的生存期,但却无法具体了解如何清理资源。Although the garbage collector is able to track the lifetime of a managed object that encapsulates an unmanaged resource, it doesn't have specific knowledge about how to clean up the resource.

创建封装非托管资源的对象时,建议在公共 Dispose 方法中提供必要的代码以清理非托管资源。When you create an object that encapsulates an unmanaged resource, it's recommended that you provide the necessary code to clean up the unmanaged resource in a public Dispose method. 通过提供 Dispose 方法,对象的用户可以在使用完对象后显式释放其内存。By providing a Dispose method, you enable users of your object to explicitly free its memory when they are finished with the object. 使用封装非托管资源的对象时,务必要在需要时调用 DisposeWhen you use an object that encapsulates an unmanaged resource, make sure to call Dispose as necessary.

还必须提供一种释放非托管资源的方法,以防类型使用者忘记调用 DisposeYou must also provide a way for your unmanaged resources to be released in case a consumer of your type forgets to call Dispose. 可以使用安全句柄来包装非托管资源,也可以重写 Object.Finalize() 方法。You can either use a safe handle to wrap the unmanaged resource, or override the Object.Finalize() method.

有关清理非托管资源的详细信息,请参阅清理非托管资源For more information about cleaning up unmanaged resources, see Clean up unmanaged resources.

请参阅See also