Automatic Memory ManagementAutomatic Memory Management

자동 메모리 관리는 관리되는 실행을 수행하는 중에 공용 언어 런타임에서 제공되는 서비스 중 하나입니다.Automatic memory management is one of the services that the Common Language Runtime provides during Managed Execution. CLR의 가비지 수집기에서 애플리케이션의 메모리 할당과 해제를 관리합니다.The Common Language Runtime's garbage collector manages the allocation and release of memory for an application. 즉, 관리되는 애플리케이션을 개발할 때 개발자는 메모리 관리 작업을 수행하기 위해 코드를 작성할 필요가 없습니다.For developers, this means that you do not have to write code to perform memory management tasks when you develop managed applications. 자동 메모리 관리를 사용하면 실수로 개체 비우기를 수행하지 않거나 메모리 누수를 유발하거나 또는 이미 비워진 개체를 찾기 위해 메모리에 액세스하려는 경우 등의 일반적인 문제를 해결할 수 있습니다.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 has already been freed. 이 단원에서는 가비지 수집기에서 메모리를 할당하고 해제하는 방법에 대해 설명합니다.This section describes how the garbage collector allocates and releases memory.

메모리 할당Allocating Memory

사용자가 새 프로세스를 시작하면 런타임에서는 인접한 주소 공간 영역을 이 프로세스에 예약합니다.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 is 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 very quickly.

메모리 해제Releasing Memory

가비지 수집기의 최적화 엔진은 수행 중인 할당에 따라 수집을 수행하기에 가장 적합한 시간을 결정합니다.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. 모든 애플리케이션에는 여러 개의 루트가 있습니다.Every application has a set of roots. 각 루트는 관리되는 힙에 있는 개체를 참조하거나 Null로 설정됩니다.Each root either refers to an object on the managed heap or is set to null. 애플리케이션 루트에는 정적 필드, 스레드 스택의 지역 변수와 매개 변수 및 CPU 레지스터가 포함되어 있습니다.An application's roots include static fields, local variables and parameters on a thread's stack, and CPU registers. 가비지 수집기는 JIT(Just-In-Time) 컴파일러와 런타임에서 관리하는 활성 루트 목록에 액세스할 수 있습니다.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, it examines an application's roots, and in the process 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 will release 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. 수집을 수행하는 동안 연결할 수 없는 개체의 수가 엄청나게 발견되는 경우에만 메모리를 압축한다는 점에 주목합니다.Note that 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 not compacted.

세대 및 성능Generations and Performance

가비지 수집기의 성능을 최적화하기 위해 관리되는 힙은 0세대, 1세대 및 2세대의 3개 세대로 나뉩니다.To optimize the performance of the garbage collector, the managed heap is divided into three generations: 0, 1, and 2. 런타임의 가비지 수집 알고리즘은 컴퓨터 소프트웨어 업계의 가비지 수집 체계 실험을 통해 밝혀진 일반 사실을 기반으로 하고 있습니다.The runtime's garbage collection algorithm is based on several generalizations that the computer software industry has discovered to be true by experimenting with garbage collection schemes. 첫째로, 가비지 수집기는 관리되는 전체 힙보다 관리되는 일부 힙에서 더 빠르게 메모리를 압축할 수 있습니다.First, it is faster to compact the memory for a portion of the managed heap than for the entire managed heap. 둘째로, 개체가 새로울수록 수명은 더 짧아지고 개체가 오래될수록 수명은 더 길어집니다.Secondly, newer objects will have shorter lifetimes and older objects will have longer lifetimes. 마지막으로, 새로운 개체일수록 서로 연결되는 경향이 있어서 애플리케이션에서 거의 동시에 액세스됩니다.Lastly, newer objects tend to be related to each other and accessed by the application around the same time.

런타임 가비지 수집기는 새 개체를 0세대에 저장합니다.The runtime's 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. 개체 승격 과정은 이 단원의 마지막 부분에서 설명하고 있습니다.The process of object promotion is described later in this topic. 전체 힙보다 일부 관리되는 힙을 압축하는 것이 더 빠르기 때문에 가비지 수집기는 수집을 수행할 때마다 이 체계를 사용하여 전체 관리되는 힙에서 메모리를 해제하는 대신 특정 세대에서 메모리를 해제할 수 있습니다.Because it is 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이 가득 차면 수집을 수행합니다.In reality, the garbage collector performs a collection when generation 0 is full. 애플리케이션에서 새 개체를 만들려고 할 때 세대 0이 가득 찬 경우, 가비지 수집기에서는 개체 할당할 주소 공간이 세대 0에 존재하지 않음을 감지합니다.If an application attempts to create a new object when generation 0 is full, the garbage collector discovers that there is no address space remaining in generation 0 to allocate for the object. 그러면 가비지 수집기는 이 개체를 위해 세대 0에서 주소 공간을 비우기 위해 수집을 수행합니다.The garbage collector performs a collection in an attempt to free address space in generation 0 for the object. 가비지 수집기는 관리되는 힙에서 모든 개체를 검사하는 대신 먼저 세대 0에서 개체를 검사합니다.The garbage collector starts by examining the objects in generation 0 rather than all objects in the managed heap. 이 방식은 가장 효율적인 방식입니다. 왜냐하면 새 개체의 수명은 짧은 성향이 있으며 수집이 수행되면 세대 0의 상당수 개체는 더 이상 애플리케이션에서 사용되지 않을 것이기 때문입니다.This is the most efficient approach, because new objects tend to have short lifetimes, and it is expected that many of the objects in generation 0 will no longer be in use by the application when a collection is performed. 또한, 세대 0에만 컬렉션을 수행하더라도 애플리케이션에서 새 개체를 계속 만들 수 있는 충분한 메모리를 확보하기도 합니다.In addition, a collection of generation 0 alone often reclaims enough memory to allow the application to continue creating new objects.

가비지 수집기에서는 0세대 컬렉션을 수행한 후 앞서의 메모리 해제에서 설명한 대로 연결할 수 있는 개체의 메모리를 압축합니다.After the garbage collector performs a collection of generation 0, it compacts the memory for the reachable objects as explained in Releasing Memory earlier in this topic. 그런 다음 가비지 컬렉션기는 이 개체를 승격시켜서 이 부분의 관리되는 힙을 세대 1로 간주합니다.The garbage collector then promotes these objects and considers this portion of the managed heap 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에서 개체를 다시 검사할 필요가 없습니다.As a result, the garbage collector does not have to reexamine the objects in generations 1 and 2 each time it performs a collection of generation 0.

가비지 수집기는 세대 0에 처음으로 수집을 수행한 다음 연결할 수 있는 개체들을 세대 1로 승격시키지만, 아직도 관리되는 힙에 남아있는 개체들은 세대 0으로 간주합니다.After the garbage collector performs its first collection of generation 0 and promotes the reachable objects to generation 1, it considers the remainder of the managed heap generation 0. 가비지 수집기는 세대 0이 가득 차거나 다른 수집을 수행할 필요가 있을 때까지 세대 0에서 새 개체에 대한 메모리 할당을 계속합니다.It continues to allocate memory for new objects in generation 0 until generation 0 is full and it is necessary to perform another collection. 이 시점에서 가비지 수집기의 최적화 엔진은 이전 세대에서 개체를 검사할 필요가 있는지를 결정합니다.At this point, the garbage collector's optimizing engine determines whether it is necessary to examine the objects in older generations. 예를 들어, 세대 0에서 수집을 수행했음에도 불구하고 애플리케이션에서 새 개체를 성공적으로 만드는 데 필요한 충분한 메모리를 확보할 수 없는 경우, 가비지 수집기는 세대 1에서 세대 2의 순서로 수집을 수행할 수 있습니다.For example, if a collection of generation 0 does not reclaim enough memory for the application to successfully complete its attempt to create a new object, the garbage collector can perform a collection of generation 1, then generation 2. 여기에서도 충분한 메모리를 확보할 수 없다면, 가비지 수집기는 세대 2, 1, 0의 순서로 수집을 수행할 수 있습니다.If this does not reclaim enough memory, the garbage collector can perform a collection of generations 2, 1, and 0. 각 수집이 완료되면 가비지 수집기는 세대 0에 있는 연결할 수 있는 개체를 압축하여 세대 1로 승격시킵니다.After each collection, the garbage collector compacts the reachable objects in generation 0 and promotes them to generation 1. 또한, 수집이 완료된 후에 세대 1에 존재하는 개체를 세대 2로 승격시킵니다.Objects in generation 1 that survive collections are promoted to generation 2. 가비지 수집기는 세 가지 세대만을 지원합니다. 따라서 수집이 완료된 후에 세대 2에 존재하는 개체는 상위 세대로 승격시킬 없으므로, 다음 수집에서 연결할 수 없는 개체로 결정될 때까지 세대 2에 보관됩니다.Because the garbage collector supports only three generations, objects in generation 2 that survive a collection remain in generation 2 until they are determined to be unreachable in a future collection.

관리되지 않는 리소스의 메모리 할당 해제Releasing Memory for Unmanaged Resources

가비지 수집기는 사용자 애플리케이션에서 만들어지는 대부분의 개체에 대해 메모리 관리 작업을 자동으로 수행할 수 있습니다.For the majority of the objects that your application creates, you can rely on the garbage collector 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 does not have specific knowledge about how to clean up the resource. 관리되지 않는 리소스를 캡슐화해 주는 개체를 만드는 경우 관리되지 않는 리소스를 정리하는 데 필요한 코드를 공용 Dispose 메서드에 제공하는 것이 좋습니다.When you create an object that encapsulates an unmanaged resource, it is 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. 관리되지 않는 리소스를 캡슐화해 주는 개체를 사용하는 경우 사용자는 Dispose 메서드를 알아 두고 필요한 경우 이 메서드를 호출해야 합니다.When you use an object that encapsulates an unmanaged resource, you should be aware of Dispose and call it as necessary. 관리되지 않는 리소스 정리 및 Dispose를 구현하는 디자인 패턴 예제에 대해서는 가비지 수집을 참조하세요.For more information about cleaning up unmanaged resources and an example of a design pattern for implementing Dispose, see Garbage Collection.

참고 항목See also