Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)

windbg - SOS DumpClass/DumpMT의 "Vtable Slots", "Total Method Slots", "Slots in VTable" 값에 대한 의미

windbg에서 System.String 타입에 대해 DumpClass 명령을 수행해 보겠습니다.

0:000> !DumpClass 00007ff961df50e0
Class Name:      System.String
mdToken:         0000000002000073
File:            C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Parent Class:    00007ff961df5188
Module:          00007ff961df1000
Method Table:    00007ff9624f6948
Vtable Slots:    1b
Total Method Slots:  1d
Class Attributes:    102101  
Transparency:        Transparent
NumInstanceFields:   2
NumStaticFields:     1
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ff9624f9288  400026f        8         System.Int32  1 instance           m_stringLength
00007ff9624f7b00  4000270        c          System.Char  1 instance           m_firstChar
00007ff9624f6948  4000274       90        System.String  0   shared           static Empty
                                 >> Domain:Value  000002c18d980b20:NotInit  <<

위와 같이 "Vtable Slots"와 "Total Method Slots" 값이 나옵니다. "Vtable"이라는 단어로 봐서 분명 가상 메서드와 관련이 있을 것 같은데,

C++의 가상 함수 테이블 (vtable)은 언제 생성될까요?
; https://www.sysnet.pe.kr/2/0/11167

C++ 클래스 상속 관계의 vtable 생성 과정
; https://www.sysnet.pe.kr/2/0/11168

2개로 나누어져 있는 이유를 모르겠습니다. 게다가 DumpMT로 System.String 타입의 메서드 테이블을 살펴보면,

0:000> !DumpMT 00007ff9624f6948
EEClass:         00007ff961df50e0
Module:          00007ff961df1000
Name:            System.String
mdToken:         0000000002000073
File:            C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
BaseSize:        0x18
ComponentSize:   0x2
Slots in VTable: 194
Number of IFaces in IFaceMap: 7

"Slots in VTable"이란 값도 나옵니다. 이렇게 3가지로 나누어져 있다 보니 더욱 혼란스럽습니다. ^^;

이 중에서 "Slots in VTable"은 "!DumpMT -md <addr>" 명령을 내리면 그 의미를 확실히 알 수 있습니다. 왜냐하면 실제로 194개의 메서드 목록이 나오기 때문입니다. 그럼 한 가지는 정리되었군요. ^^ "Slots in VTable" 값이야말로 해당 타입이 (상속을 포함해) 소유하고 있는 전체 메서드의 수를 가리킵니다.

남은 것은 "Vtable Slots"와 "Total Method Slots"의 의미인데요. 이게 좀 재미있습니다. ^^




참고로 검색해 보면 다음과 같은 질문 글이 나옵니다.

SOS and DumpClass
; https://social.msdn.microsoft.com/Forums/vstudio/en-US/13839da8-bc06-4443-9a1b-5e326e386ff8/sos-and-dumpclass?forum=clr

정리하면, 너무 난이도가 있는 질문이라 더 진행하려면 "유료" 기술 지원을 신청해야 한다는 답변이 나옵니다. 그래서 저도 그냥 접을까 하다가 호기심이 생겨 ^^; 좀 더 살펴봤습니다.

우선 예를 들기 위해 다음의 코드로 시작해 보겠습니다.

using System;

namespace ConsoleApp2
{
    class ABC
    {
    }

    class Program
    {
        static void Main(string[] args)
        {
            Dump(new ABC());
        }

        private static void Dump(ABC aBC)
        {
            Console.ReadLine();
        }
    }
}

아무것도 정의하지 않은 ABC 클래스이지만 DumpClass로 살펴보면,

0:000> !DumpClass 00cf16ec
Class Name:      ConsoleApp2.ABC
mdToken:         02000002
File:            F:\cloud_drive\Dropbox\articles\compoentSize\ConsoleApp2\ConsoleApp2\bin\Debug\ConsoleApp2.exe
Parent Class:    715445e0
Module:          00cf3ffc
Method Table:    00cf4d88
Vtable Slots:    4
Total Method Slots:  5
Class Attributes:    100000  
Transparency:        Critical
NumInstanceFields:   0
NumStaticFields:     0

"Vtable Slots == 4", "Total Method Slots == 5"가 나옵니다.

우선 결론부터 설명하면 "Vtable Slots"은 가상 함수의 수를 의미합니다. 그런데 어떻게 ABC 클래스에 4개가 있을까요? Visual Studio에서 object 타입에 대해 F12 키를 눌러 메타데이터 정의로 들어가 보면 다음과 같이 3개의 가상 함수를 확인할 수 있습니다.

using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;

namespace System
{
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class Object
    {
        [NonVersionableAttribute]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public Object();

        [NonVersionableAttribute]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        ~Object();

        [NonVersionableAttribute]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        public static bool ReferenceEquals(Object objA, Object objB);
        public virtual bool Equals(Object obj);
        public virtual int GetHashCode();
        [SecuritySafeCritical]
        public Type GetType();
        public virtual string ToString();
        [SecuritySafeCritical]
        protected Object MemberwiseClone();
    }
}

아니, 그런데 분명히 "Vtable Slots"의 값은 4로 나오는데 어째서 3일까요? 왜냐하면 ~Object로 표현된 소멸자가 실은 다음과 같이 가상 함수이기 때문입니다.

// .NET Reflector 등을 통해 보면 virtual 메서드로 나옴

protected virtual void Finalize();

따라서 windbg의 출력 결과인 4가 맞습니다. 그렇다면 "Vtable Slots"이 가상 함수의 수라는 것은 알겠는데 뜬금없이 "Total Method Slots == 5"가 나오는 것은 왜일까요?

그것은 기본 생성자(ctor)와 기본 정적 생성자(cctor)가 "Total Method Slots"의 수에 포함되기 때문입니다. ABC 클래스의 경우 기본 생성자가 정의되어 있기 때문에 5가 나오는 것입니다. 그런데 재미있는 것은 일반 생성자를 하나 정의해서 기본 생성자의 자동 추가를 막게 되면,

class ABC
{
    public ABC(char ch) { }
}

이번에는 ctor가 없어졌으므로 다음과 같은 상태로 바뀝니다.

Vtable Slots = 4
Total Method Slots = 4

물론 다시 기본 생성자를 추가하면 Total Method Slots는 5로 바뀝니다.

class ABC
{
    public ABC(char ch) { }
    public ABC() { }
}

/*
Vtable Slots = 4
Total Method Slots = 5
*/

즉, 다른 생성자들은 전혀 상관이 없고 오직 기본 생성자에 한해서만 Total Method Slots의 수가 바뀌는 것입니다.

마찬가지로 정적 생성자도 Total Method Slots의 수에 반영됩니다.

class ABC
{
    public ABC(char ch) { }
    public ABC() { }

    // 또는 정적 생성자가 생성되도록 유발하는 정적 필드 초기화가 있는 경우에도!
    static ABC()
    {
    }
}
/*
Vtable Slots = 4
Total Method Slots = 6
*/




자, 그럼 이 지식들을 바탕으로 System.String을 다시 볼까요? ^^

정리하면 System.String은 다음과 같은 수치를 보입니다.

Vtable Slots:    1b (0n27)
Total Method Slots:  1d (0n29)
Slots in VTable: 194

그럼 수치들을 한번 맞춰보겠습니다. 우선 string은 다음과 같은 가상 메서드들을 구현하고 있습니다.

System.Object로부터 4개
IComparable로부터 1개
ICloneable로부터 1개
IConvertible로부터 17개
IEnumerable로부터 1개
IComparable<String>로부터 1개
IEnumerable<char>로부터 1개
IEquatable<String>로부터 1개
====
총 27개

그렇다면 "Vtable slots = 0x1b(0n27)"은 만족합니다. 그런데 Total Method Slots의 수가 29가 나오다니... 이건 좀 이상하군요. 분명히 System.String에는 기본 생성자도, 정적 생성자도 없기 때문에 Total Method Slots의 수도 27이 나와야 맞습니다.

당연하겠지만 여기서 고려하지 않은 조건이 있습니다. 바로 '제네릭' 메서드가 "Total Method Slots"에 반영된다는 점입니다. System.String을 보면 이런 메서드로 2개가 나옵니다.

public static String Join<T>(String separator, IEnumerable<T> values);
public static String Concat<T>(IEnumerable<T> values);

따라서 이것까지 고려해 Total Method Slots = 29가 나오는 것입니다.

확인을 위해 ABC 클래스를 이용해 다음과 같이 테스트해 볼 수 있습니다.

class ABC
{
    public ABC(char ch) { }
    public ABC() { }

    static ABC()
    {
    }

    void Test<T>(List<T> arg) { }
    void Test2<T>(List<T> arg) { }
}

/*
Vtable Slots = 4
Total Method Slots = 8 (Vtable Slots 4 + default ctor 1 + cctor 1 + generic method 2)
*/

정리가 되고 나니... 저도 마음이 편하군요. ^^




참고로, !DumpMT -md 명령어는 Vtable Slots, Total Method Slots, Slots in VTable에 속하는 메서드의 종류별로 묶어서 출력을 해줍니다. 가령 ABC 클래스를 다음과 같이 정의해 주면,

class ABC
{
    public ABC(char ch) { }
    public ABC() { }

    static ABC()
    {
    }

    void Test<T>(List<T> arg) { }
    void Test2<T>(List<T> arg) { }

    void MyMethod() { }
    static void StaticMyMethod() { }
}

!DumpMT -md의 출력은 다음과 같이 분류가 되어 출력됩니다.

the_number_of_method_1.png




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/10/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 61  62  63  64  [65]  66  67  68  69  70  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
12022정성태9/12/201915798개발 환경 구성: 458. C# 8.0 (Preview) 신규 문법을 위한 개발 환경 구성 [3]
12021정성태9/12/201927749도서: 시작하세요! C# 8.0 프로그래밍 [4]
12020정성태9/11/201914511VC++: 134. SYSTEMTIME 값 기준으로 특정 시간이 지났는지를 판단하는 함수
12019정성태9/11/20199860Linux: 23. .NET Core + 리눅스 환경에서 Environment.CurrentDirectory 접근 시 주의 사항
12018정성태9/11/20198845오류 유형: 567. IIS - Unrecognized attribute 'targetFramework'. Note that attribute names are case-sensitive. (D:\lowSite4\web.config line 11)
12017정성태9/11/201911901오류 유형: 566. 비주얼 스튜디오 - Failed to register URL "http://localhost:6879/" for site "..." application "/". Error description: Access is denied. (0x80070005)
12016정성태9/5/201912858오류 유형: 565. git fetch - warning: 'C:\ProgramData/Git/config' has a dubious owner: '(unknown)'.
12015정성태9/3/201916749개발 환경 구성: 457. 윈도우 응용 프로그램의 Socket 연결 시 time-out 시간 제어
12014정성태9/3/201911194개발 환경 구성: 456. 명령행에서 AWS, Azure 등의 원격 저장소에 파일 관리하는 방법 - cyberduck/duck 소개
12013정성태8/28/201913985개발 환경 구성: 455. 윈도우에서 (테스트) 인증서 파일 만드는 방법 [3]
12012정성태8/28/201917870.NET Framework: 859. C# - HttpListener를 이용한 HTTPS 통신 방법
12011정성태8/27/201916111사물인터넷: 57. C# - Rapsberry Pi Zero W와 PC 간 Bluetooth 통신 예제 코드파일 다운로드1
12010정성태8/27/201911349VS.NET IDE: 138. VSIX - DTE.ItemOperations.NewFile 메서드에서 템플릿 이름을 다국어로 설정하는 방법
12009정성태8/26/201911926.NET Framework: 858. C#/Windows - Clipboard(Ctrl+C, Ctrl+V)가 동작하지 않는다면?파일 다운로드1
12008정성태8/26/201911703.NET Framework: 857. UWP 앱에서 SQL Server 데이터베이스 연결 방법
12007정성태8/24/201910850.NET Framework: 856. .NET Framework 버전을 올렸을 때 오류가 발생할 수 있는 상황
12006정성태8/23/201914072디버깅 기술: 129. guidgen - Encountered an improper argument. 오류 해결 방법 (및 windbg 분석) [1]
12005정성태8/13/201912034.NET Framework: 855. 닷넷 (및 VM 계열 언어) 코드의 성능 측정 시 주의할 점 [2]파일 다운로드1
12004정성태8/12/201919836.NET Framework: 854. C# - 32feet.NET을 이용한 PC 간 Bluetooth 통신 예제 코드 [14]
12003정성태8/12/201912575오류 유형: 564. Visual C++ 컴파일 오류 - fatal error C1090: PDB API call failed, error code '3'
12002정성태8/12/201911568.NET Framework: 853. Excel Sheet를 WinForm에서 사용하는 방법 - 두 번째 이야기 [5]
12001정성태8/10/201916079.NET Framework: 852. WPF/WinForm에서 UWP의 기능을 이용해 Bluetooth 기기와 Pairing하는 방법 [1]
12000정성태8/9/201914938.NET Framework: 851. WinForm/WPF에서 Console 창을 띄워 출력하는 방법파일 다운로드1
11999정성태8/1/201910695오류 유형: 563. C# - .NET Core 2.0 이하의 Unix Domain Socket 사용 시 System.IndexOutOfRangeException 오류
11998정성태7/30/201911904오류 유형: 562. .NET Remoting에서 서비스 호출 시 SYN_SENT로 남는 현상파일 다운로드1
11997정성태7/30/201913439.NET Framework: 850. C# - Excel(을 비롯해 Office 제품군) COM 객체를 제어 후 Excel.exe 프로세스가 남아 있는 문제 [2]파일 다운로드1
... 61  62  63  64  [65]  66  67  68  69  70  71  72  73  74  75  ...