.NET GC - 하위 세대의 객체를 포함하는 상위 세대의 참조를 추적하기 위한 card-table
GC의 동작 원리에 대해 쉽게 설명한 시리즈 글이 있어서 소개합니다. ^^
Back to basic: Series on dynamic memory management
; https://learn.microsoft.com/en-us/archive/blogs/abhinaba/back-to-basic-series-on-dynamic-memory-management
위의 글을 시작으로 현재 9개의 글이 쓰여졌는데 나름 재미있습니다.
- Memory allocation, a walk down the history
- Why use garbage collection
- Reference Counting Garbage Collection
- Mark-sweep garbage collection
- Copying garbage collection
- Optimizing reference counting garbage collection
- Handling overflow in mark stage
- Generational Garbage Collection
- How does the GC find object references
C# - 생성한 참조 개체가 언제 GC의 정리 대상이 될까요?
; https://www.sysnet.pe.kr/2/0/13052
이 중에서 Young 세대의 객체가 Old 세대의 객체에 할당된 경우, 그것을 추적하기 위한 방법을 설명한 "
Generational Garbage Collection" 글을 읽으면서 확인하고 싶은 것이 생겼습니다.
위의 설명에 의하면, 아래와 같은 대입이 발생하는 경우 Card-table에 대한 액세스를 하기 위한 부가적인 호출이 JIT 컴파일러에 의해 삽입되어야 합니다. (글에 보면, .NET JITer가 그런 코드를 추가한다고 합니다.)
class Program
{
public InnerType In;
static void Main(string[] args)
{
Program pg = new Program();
InnerType instance = new InnerType();
pg.In = instance;
}
}
class InnerType
{
}
실제로 그런지 어디 테스트 해볼까요? 비교를 위해 위의 코드를 다음과 같이 확장해 보겠습니다.
class Program
{
public InnerType In;
public int valueIn;
static void Main(string[] args)
{
Program pg = new Program();
InnerType stackVar = null;
InnerType instance = new InnerType();
InnerType stackInstance = new InnerType();
pg.In = instance;
pg.valueIn = 5;
stackVar = stackInstance;
}
}
class InnerType
{
}
"pg.valueIn = 5" 코드는 참조형이 아니기 때문에 card-table에 대한 액세스 코드가 없어야 합니다. 또한 "stackVar = stackInstance" 대입도 스택 변수에 할당되는 것이므로 역시 card-table 액세스 코드는 없어야 합니다.
이제 빌드하고, Visual Studio에서 Disassembly 창을 통해 확인해 보면? ^^
pg.In = instance;
02B900E5 mov edx,dword ptr [ebp-40h]
02B900E8 mov eax,dword ptr [ebp-48h]
02B900EB lea edx,[edx+4]
02B900EE call clr!JIT_WriteBarrierEAX (73711B70)
pg.valueIn = 5;
02B900F3 mov eax,dword ptr [ebp-40h]
02B900F6 mov dword ptr [eax+8],5
stackVar = stackInstance;
02B900FD mov eax,dword ptr [ebp-4Ch]
02B90100 mov dword ptr [ebp-44h],eax
정말 그렇군요. 아마도 저 호출이 card-table에 표시를 하기 위한 CLR 내부 코드로의 호출이지 않을까 예상해봅니다. 가끔, 관리 코드를 어셈블리 수준에서 디버깅하다 보면 저런 이상한 호출들이 끼워져 있는 것을 볼 수 있었는데, 이제야 그 원인을 이해하게 되었군요. ^^
간단한 테스트였지만... 역시나 '마법은 없다'는 것!
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]