C# - GC Heap에 위치한 참조 개체의 주소를 알아내는 방법
예전에 아래의 글을 설명하면서,
C#에서 확인해 보는 관리 힙의 인스턴스 구조
; https://www.sysnet.pe.kr/2/0/1176
참조 개체가 관리 힙의 어디에 위치하고 있는지 그 주솟값을 구하기 위해 fixed를 사용하려고 억지로 필드 하나를 정의하는 코드를 사용했는데요,
// x86 환경
class Program
{
public int value = 0xff;
static unsafe void Main(string[] args)
{
Program pg = new Program();
fixed (int* p2 = &pg.value)
{
Console.WriteLine("OBJECT Header(SyncBlock Index): " + (*(p2 - 2)).ToString("x"));
Console.WriteLine("MethodTable Address: " + (*(p2 - 1)).ToString("x"));
Console.WriteLine("첫 번째 필드 값: " + (*(p2 - 0)).ToString("x"));
}
}
}
이후로 몇몇 글에서 __makeref를 이용해 참조 주솟값을 구하는 방법을 사용했었지만,
windbg/sos - Dictionary의 entries 배열 내용을 모두 덤프하는 방법 (do_hashtable.py)
; https://www.sysnet.pe.kr/2/0/12087
직접적으로 명시를 하지 않아 검색이 잘 되는군요. ^^ 그래서 검색의 목적을 위해, 아울러 혹시 궁금하신 분들을 위해 별도 제목으로 뽑아 이렇게 기록을 남깁니다. 방법은 간단하게 TypedReference와 __makeref를 이용해 다음과 같이 구할 수 있습니다.
// x86 or x64
using System;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
public int value = 0xff;
static unsafe void Main(string[] args)
{
Program pg = new Program();
IntPtr ptr = GetRefAddress(pg);
}
private unsafe static IntPtr GetRefAddress(object obj)
{
TypedReference refA = __makeref(obj);
return **(IntPtr**)&refA;
}
/* 또는, Dumping the managed heap in C#
public static nint GetAddress(T obj)
{
// Get the address of the reference, cast it to a pointer,
// then dereference it to get the address of the object
return (nint)(*(T**)&obj);
}
*/
}
}
이 코드를 기반으로 "
C#에서 확인해 보는 관리 힙의 인스턴스 구조" 글에 사용한 코드를 다시 작성해 보면,
static unsafe void WriteRefObjectInfo(IntPtr pAddress)
{
IntPtr pHeader = pAddress - (IntPtr.Size * 1);
Console.WriteLine("OBJECT Header(SyncBlock Index): " + GetWordAsText(pHeader));
Console.WriteLine("MethodTable Address: " + GetWordAsText(pAddress));
IntPtr pIntValue = pAddress + (IntPtr.Size * 1);
Console.WriteLine("첫 번째 int 필드 값: " + GetWordAsText(pIntValue));
}
static unsafe string GetWordAsText(IntPtr pAddress)
{
if (IntPtr.Size == 4)
{
return (*((int*)pAddress.ToPointer())).ToString("x");
}
else
{
return (*((long*)pAddress.ToPointer())).ToString("x");
}
}
다음과 같이 값이 잘 출력되는 것을 확인할 수 있습니다.
OBJECT Header(SyncBlock Index): 0
MethodTable Address: 7ff8566f5a70
첫 번째 int 필드 값: ff
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]