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

비밀번호

댓글 작성자
 




... 31  32  33  34  35  36  37  38  39  40  41  42  43  [44]  45  ...
NoWriterDateCnt.TitleFile(s)
12520정성태1/30/20218240개발 환경 구성: 526. 오라클 클라우드의 VM에 ping ICMP 여는 방법
12519정성태1/30/20217374개발 환경 구성: 525. 오라클 클라우드의 VM을 외부에서 접근하기 위해 포트 여는 방법
12518정성태1/30/202124813Linux: 37. Ubuntu에 Wireshark 설치 [2]
12517정성태1/30/202112379Linux: 36. 윈도우 클라이언트에서 X2Go를 이용한 원격 리눅스의 GUI 접속 - 우분투 20.04
12516정성태1/29/20219037Windows: 188. Windows - TCP default template 설정 방법
12515정성태1/28/202110207웹: 41. Microsoft Edge - localhost에 대해 http 접근 시 무조건 https로 바뀌는 문제 [3]
12514정성태1/28/202110544.NET Framework: 1021. C# - 일렉트론 닷넷(Electron.NET) 소개 [1]파일 다운로드1
12513정성태1/28/20218572오류 유형: 698. electronize - User Profile 디렉터리에 공백 문자가 있는 경우 빌드가 실패하는 문제 [1]
12512정성태1/28/20218390오류 유형: 697. The program can't start because VCRUNTIME140.dll is missing from your computer. Try reinstalling the program to fix this problem.
12511정성태1/27/20218126Windows: 187. Windows - 도스 시절의 8.3 경로를 알아내는 방법
12510정성태1/27/20218493.NET Framework: 1020. .NET Core Kestrel 호스팅 - Razor 지원 추가 [1]파일 다운로드1
12509정성태1/27/20219471개발 환경 구성: 524. Jupyter Notebook에서 C#(F#, PowerShell) 언어 사용을 위한 환경 구성 [3]
12508정성태1/27/20218073개발 환경 구성: 523. Jupyter Notebook - Slide 플레이 버튼이 없는 경우
12507정성태1/26/20218185VS.NET IDE: 157. Visual Studio - Syntax Visualizer 메뉴가 없는 경우
12506정성태1/25/202111421.NET Framework: 1019. Microsoft.Tye 기본 사용법 소개 [1]
12505정성태1/23/20219226.NET Framework: 1018. .NET Core Kestrel 호스팅 - Web API 추가 [1]파일 다운로드1
12504정성태1/23/202110351.NET Framework: 1017. .NET 5에서의 네트워크 라이브러리 개선 (2) - HTTP/2, HTTP/3 관련 [1]
12503정성태1/21/20218603오류 유형: 696. C# - HttpClient: Requesting HTTP version 2.0 with version policy RequestVersionExact while HTTP/2 is not enabled.
12502정성태1/21/20219327.NET Framework: 1016. .NET Core HttpClient의 HTTP/2 지원파일 다운로드1
12501정성태1/21/20218406.NET Framework: 1015. .NET 5부터 HTTP/1.1, 2.0 선택을 위한 HttpVersionPolicy 동작 방식파일 다운로드1
12500정성태1/21/20218985.NET Framework: 1014. ASP.NET Core(Kestrel)의 HTTP/2 지원 여부파일 다운로드1
12499정성태1/20/202110207.NET Framework: 1013. .NET Core Kestrel 호스팅 - 포트 변경, non-localhost 접속 지원 및 https 등의 설정 변경 [1]파일 다운로드1
12498정성태1/20/20219151.NET Framework: 1012. .NET Core Kestrel 호스팅 - 비주얼 스튜디오의 Kestrel/IIS Express 프로파일 설정
12497정성태1/20/202110044.NET Framework: 1011. C# - OWIN Web API 예제 프로젝트 [1]파일 다운로드2
12496정성태1/19/20218919.NET Framework: 1010. .NET Core 콘솔 프로젝트에서 Kestrel 호스팅 방법 [1]
12495정성태1/19/202111044웹: 40. IIS의 HTTP/2 지원 여부 - h2, h2c [1]
... 31  32  33  34  35  36  37  38  39  40  41  42  43  [44]  45  ...