관리, 비관리 코드는 메모리 관리를 다루는 방식이 다른 2가지 종류이다. 차이점과 garbage collection에 대해 살펴보자.
관리코드란?
관리코드란 런타임 환경에서 자동으로 메모리 관리(garbage collection, GC)를 제공하는 코드이다.
GC는 런타임 환경에서 자동으로 메모리 관리를 하는 프로세스이다. 메모리 할당과 해제에 대한 걱정없이 코드를 작성할 수 있도록 해준다.
public class ManagedMemoryManager
{
private readonly List<int> _numbers;
public ManagedMemoryManager()
{
_numbers = new List<int>();
}
public void AllocateMemory()
{
for (var i = 0; i < 1000000; i++)
{
_numbers.Add(i);
}
}
}
constructor에서 List<int> object를 초기화하는 class가 있다. 초기화된 object에 숫자를 백만개 추가하므로 memory를 할당한다.
var memoryManager = new ManagedMemoryManager();
var memoryBeforeAllocation = GC.GetTotalMemory(false);
memoryManager.AllocateMemory();
var memoryAfterAllocation = GC.GetTotalMemory(false);
Console.WriteLine($"Memory Allocated to the list: {memoryAfterAllocation - memoryBeforeAllocation} bytes");
// output
// Memory Allocated to the list: 6289160 bytes
AllocateMemory()함수에 의해 메모리가 얼만큼 할당 되었는지 확인할 수 있다.
ManagedMemoryManager instance가 더 이상 사용되지 않으면, GC는 이를 감지하고 _numbers list에 할당되었던 메모리를 해제한다.
관리코드의 메모리 관리
new object를 생성하면 runtime 환경은 heap에 object를 위한 memory를 할당한다. object가 더 이상 필요하지 않으면 runtime 환경은 object를 위한 memory를 해제한다.
관리코드의 중요한 부분은 종속성 주입이다. 메모리에 object의 생애주기를 명시하므로 종속성 주입을 사용할 수 있다. 메모리에 objects를 계속 갖고 있으면, 성능에 문제가 될 수 있다.
생애주기는 Transient, Scoped, Singleton을 포함한다. 각 object에 적절한 생애주기를 사용하므로, 코드를 효율적이고 메모리 이슈를 줄일 수 있다.
관리코드의 장단점
런타임 환경이 메모리 관리를 담당하기 떄문에, 메모리 이슈가 잘 발생하지 않는다. buffer overflow와 다른 보안이슈를 방지하기 위한 추가적인 보안확인도 수행한다.
다른 장점은 이식성이다. 관리코드로 작성된 앱은 런타임 환경을 지원하는 어떠한 platform에서든 작동된다. 예를들어 C#으로 작성된 코드는 IL로 컴파일된다. C#프로그램이 실행되면 어셈블리가 CLR(Common Language Runtime)에 로드되고 CLR은 Just-In-Time 컴파일을 실행하여 IL코드를 Machine code로 변환합니다.
가장 큰 단점은 메모리의 제한된 제어이다. 섬세한 제어를 원하는 경우 단점이 될 수 있다. 추가로 GC는 성능 오버헤드를 발생할 수 있다. 주기적으로 objects의 사용여부를 스캔한다.
비관리코드란?
메모리관리 외부나, .NET 런타임이 제공하는 보안기능 외부에서 작동하는 코드이다. 메모리 할당과 해제를 직접 관리해야한다.
보통 C, C++ 같은 언어가 비관리코드이다. 특정 플랫폼과 구조에 특화된 machine code로 직접 컴파일된다. 하지만 C#으로도 비관리코드를 작성할 수 있다. unsafe context에서 native code와의 작업과 관련되어 있다.
비관리코드는 하드웨어에 특화되어 있으며, 몇몇 케이스에서 향상된 성능을 보여준다.
Unsafe Context
C#의 unsafe 키워드는 .NET runtime에서 제공하는 보안 기능을 통과하고 바로 pointers와 동작한다. 가끔 low-level 동작이나 비관리 메모리와 작업할 때 사용한다.
var numbers = new int[] { 1, 2, 3, 4, 5 };
unsafe
{
fixed (int* ptr = numbers)
{
for (var i = 0; i < 5; i++)
{
Console.WriteLine(*(ptr + i));
}
}
}
array의 element에 접근하기 위해 pointer를 사용하였다. fixed는 메모리에서 numbers 배열을 고정시키고, GC에 의해 움직이지 않도록 한다.
하지만, unsafe code는 buffer overflows나 메모리누수, 보안 이슈가 생길 수 있으므로, 꼭 필요한 경우에만 주의해서 사용해야 한다.
비관리코드와 작업
C#은 DllImport attribute를 통해 비관리코드와 작업할 수 있도록 한다. 이 attribute는 native 라이브러리의 function을 관리코드에서 사용할 수 있도록 한다.
'C#' 카테고리의 다른 글
C#] Optional Parameters (0) | 2024.02.14 |
---|---|
C#] IDisposal Interface 구현 방법 (0) | 2024.02.14 |
C#] SOLID 원칙 5. Dependency Inversion Principle(의존성 역전 원칙) (0) | 2024.02.07 |
C#] SOLID 원칙 4. Interface Segregation Principle(인터페이스 분리 원칙) (1) | 2024.02.07 |
C#] Access Modifiers (0) | 2024.02.02 |
댓글