성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 그냥 RSS Reader 기능과 약간의 UI 편의성 때문에 사용...
[이종효] 오래된 소프트웨어는 보안 위협이 되기도 합니다. 혹시 어떤 기능...
[정성태] @Keystroke IEEE의 문서를 소개해 주시다니... +_...
[손민수 (Keystroke)] 괜히 듀얼채널 구성할 때 한번에 같은 제품 사라고 하는 것이 아...
[정성태] 전각(Full-width)/반각(Half-width) 기능을 토...
[정성태] Vector에 대한 내용은 없습니다. Vector가 닷넷 BCL...
[orion] 글 읽고 찾아보니 디자인 타임에는 InitializeCompon...
[orion] 연휴 전에 재현 프로젝트 올리자 생각해 놓고 여의치 않아서 못 ...
[정성태] 아래의 글에 정리했으니 참고하세요. C# - Typed D...
[정성태] 간단한 재현 프로젝트라도 있을까요? 저런 식으로 설명만 해...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>x64 환경에서 참조형의 기본 메모리 소비는 얼마나 될까요?</h1> <p> 지난 글이 x86 실습으로 한 것이라서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 일반 참조형의 기본 메모리 소비는 얼마나 될까요? ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/1174'>https://www.sysnet.pe.kr/2/0/1174</a> .NET Array는 왜 12bytes의 기본 메모리를 점유할까? ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/1173'>https://www.sysnet.pe.kr/2/0/1173</a> </pre> <br /> x64 환경에서 실습하는 분들은 헷갈리는 경우가 있는 듯해서 이번엔 64비트 환경에서 테스트하는 것으로 진행해 보겠습니다.<br /> <br /> 예제를 위해, 코드는 다음과 같이 작성하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > namespace ConsoleApplication1 { class MyType { } class Program { static void Main(string[] args) { MyType inst = new MyType(); Thread.Sleep(-1); } } } </pre> <br /> windbg로 확인하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:004> <span style='color: blue; font-weight: bold'>.loadby sos clr</span> 0:000> <span style='color: blue; font-weight: bold'>!name2ee ConsoleApplication1!ConsoleApplication1.MyType</span> Module: 00007fff789d4148 Assembly: ConsoleApplication1.exe Token: 0000000002000002 MethodTable: 00007fff789d5b00 EEClass: 00007fff789d25f8 Name: ConsoleApplication1.MyType 0:000> <span style='color: blue; font-weight: bold'>!dumpheap -mt 00007fff789d5b00</span> Address MT Size 0000000003e931b8 00007fff789d5b00 24 Statistics: MT Count TotalSize Class Name 00007fff789d5b00 1 24 ConsoleApplication1.MyType Total 1 objects 0:000> <span style='color: blue; font-weight: bold'>!do 0000000003e931b8</span> Name: ConsoleApplication1.MyType MethodTable: 00007fff789d5b00 EEClass: 00007fff789d25f8 <span style='color: blue; font-weight: bold'>Size: 24(0x18) bytes</span> File: C:\temp\ConsoleApplication1\bin\x64\Debug\ConsoleApplication1.exe Fields: None 0:000> <span style='color: blue; font-weight: bold'>!dumpclass 00007fff789d25f8</span> Class Name: ConsoleApplication1.MyType mdToken: 0000000002000002 File: C:\temp\ConsoleApplication1\bin\x64\Debug\ConsoleApplication1.exe Parent Class: 00007fffd4372f68 Module: 00007fff789d4148 Method Table: 00007fff789d5b00 Vtable Slots: 4 Total Method Slots: 5 Class Attributes: 100000 Transparency: Critical NumInstanceFields: 0 NumStaticFields: 0 0:000> <span style='color: blue; font-weight: bold'>dq 0000000003e931b8</span> 00000000`03e931b8 00007fff`789d5b00 00000000`00000000 00000000`03e931c8 00000000`00000000 00000000`00000000 00000000`03e931d8 00000000`00000000 00000000`00000000 00000000`03e931e8 00000000`00000000 00000000`00000000 00000000`03e931f8 00000000`00000000 00000000`00000000 00000000`03e93208 00000000`00000000 00000000`00000000 00000000`03e93218 00000000`00000000 00000000`00000000 00000000`03e93228 00000000`00000000 00000000`00000000 </pre> <br /> 보시는 바와 같이, 24(0x18)bytes를 소비하고 있습니다. 왜냐하면 빈 객체라고 해도 데이터 공간으로 기본 8바이트를 점유하고 있기 때문입니다. (참고로, 00007fff`789d5b00 데이터 앞의 8바이트 위치에는 OBJECT HEADER가 위치하고 있습니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > -8 : OBJECT HEADER(예: SyncBlock Index를 담는 용도) +0 : MethodTable Address +8 : 빈 값 </pre> <br /> 그럼, int (4바이트) 형의 필드를 추가하면 어떻게 될까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > namespace ConsoleApplication1 { class MyType { <span style='color: blue; font-weight: bold'>int test = 0xFF;</span> } class Program { static void Main(string[] args) { MyType inst = new MyType(); Thread.Sleep(-1); } } } </pre> <br /> 다시 메모리 값을 확인해 보면 다음과 같이 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>!name2ee ConsoleApplication1!ConsoleApplication1.MyType</span> Module: 00007fff789f4148 Assembly: ConsoleApplication1.exe Token: 0000000002000002 MethodTable: 00007fff789f5b10 EEClass: 00007fff789f2600 Name: ConsoleApplication1.MyType 0:000> <span style='color: blue; font-weight: bold'>!dumpheap -mt 00007fff789f5b10</span> Address MT Size 00000000035131b8 00007fff789f5b10 24 Statistics: MT Count TotalSize Class Name 00007fff789f5b10 1 24 ConsoleApplication1.MyType Total 1 objects 0:000> <span style='color: blue; font-weight: bold'>!dumpclass 00007fff789f2600</span> Class Name: ConsoleApplication1.MyType mdToken: 0000000002000002 File: C:\temp\ConsoleApplication1\bin\x64\Debug\ConsoleApplication1.exe Parent Class: 00007fffd4372f68 Module: 00007fff789f4148 Method Table: 00007fff789f5b10 Vtable Slots: 4 Total Method Slots: 5 Class Attributes: 100000 Transparency: Critical NumInstanceFields: 1 NumStaticFields: 0 MT Field <span style='color: blue; font-weight: bold'>Offset</span> Type VT Attr Value Name 00007fffd43985a0 4000001 <span style='color: blue; font-weight: bold'>8</span> System.Int32 1 instance test 0:000> <span style='color: blue; font-weight: bold'>dq 00000000035131b8</span> 00000000`035131b8 00007fff`789f5b10 <span style='color: blue; font-weight: bold'>00000000`000000ff</span> 00000000`035131c8 00000000`00000000 00000000`00000000 00000000`035131d8 00000000`00000000 00000000`00000000 00000000`035131e8 00000000`00000000 00000000`00000000 00000000`035131f8 00000000`00000000 00000000`00000000 00000000`03513208 00000000`00000000 00000000`00000000 00000000`03513218 00000000`00000000 00000000`00000000 00000000`03513228 00000000`00000000 00000000`00000000 0:000> <span style='color: blue; font-weight: bold'>dd 00000000035131b8</span> 00000000`032031b8 789f5b10 00007fff <span style='color: blue; font-weight: bold'>000000ff</span> 00000000 00000000`032031c8 00000000 00000000 00000000 00000000 00000000`032031d8 00000000 00000000 00000000 00000000 00000000`032031e8 00000000 00000000 00000000 00000000 00000000`032031f8 00000000 00000000 00000000 00000000 00000000`03203208 00000000 00000000 00000000 00000000 00000000`03203218 00000000 00000000 00000000 00000000 00000000`03203228 00000000 00000000 00000000 00000000 0:000> <span style='color: blue; font-weight: bold'>!do 00000000035131b8</span> Name: ConsoleApplication1.MyType MethodTable: 00007fff789f5b10 EEClass: 00007fff789f2600 <span style='color: blue; font-weight: bold'>Size: 24(0x18) bytes</span> File: C:\temp\ConsoleApplication1\bin\x64\Debug\ConsoleApplication1.exe Fields: MT Field Offset Type VT Attr Value Name 00007fffd43985a0 4000001 8 System.Int32 1 instance 255 test </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > -8 : OBJECT HEADER(예: SyncBlock Index를 담는 용도) +0 : MethodTable Address +8 : 이후 4바이트 영역에 int 값 </pre> <br /> 필드를 하나 더 포함하고 있는데도 여전히 24bytes가 소비되고 있습니다. 왜냐하면 필드를 포함하지 않았을 때도 00000000`00000000으로 기본 포함되어 있던 영역이 사용되고 있기 때문입니다. 이 상태에서 다시 int 4바이트 필드를 하나 더 추가하면 8바이트 중 남은 4바이트를 사용하기 때문에 메모리는 여전히 24바이트가 소비됩니다. <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > -8 : OBJECT HEADER(예: SyncBlock Index를 담는 용도) +0 : MethodTable Address +8 : 이후 4바이트 영역에 int 값 +12: 이후 4바이트 영역에 int 값 </pre> <br /> 하지만 int 4바이트 필드를 하나 더 추가하면 32바이트로 늘어납니다. (즉, 8바이트 정렬 단위로 메모리가 증가합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 배열도 테스트해야겠지요? ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > { MyType[] arr0 = new MyType[0]; MyType[] arr1 = new MyType[1]; arr1[0] = new MyType(); MyType[] arr2 = new MyType[2]; arr2[0] = new MyType(); arr2[1] = new MyType(); Thread.Sleep(-1); } </pre> <br /> 이를 windbg로 확인하면 아래와 같은 결과가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>!dumpheap -stat -type ConsoleApplication1.MyType[]</span> Statistics: MT Count TotalSize Class Name 00007fff789e5bc0 3 96 ConsoleApplication1.MyType[] Total 3 objects 0:000> <span style='color: blue; font-weight: bold'>!dumpheap -mt 00007fff789e5bc0</span> Address MT Size <span style='color: blue; font-weight: bold'>00000000033631b8</span> 00007fff789e5bc0 <span style='color: blue; font-weight: bold'>24</span> <span style='color: blue; font-weight: bold'>00000000033631d0</span> 00007fff789e5bc0 <span style='color: blue; font-weight: bold'>32</span> <span style='color: blue; font-weight: bold'>0000000003363210</span> 00007fff789e5bc0 <span style='color: blue; font-weight: bold'>40</span> Statistics: MT Count TotalSize Class Name 00007fff789e5bc0 3 96 ConsoleApplication1.MyType[] Total 3 objects // 요소가 0개인 배열 0:000> <span style='color: blue; font-weight: bold'>dq 00000000033631b8-8 L3</span> 00000000`033631b0 00000000`00000000 00007fff`789e5bc0 00000000`033631c0 00000000`00000000 // 요소가 1개인 배열 0:000> <span style='color: blue; font-weight: bold'>dq 00000000033631d0-8 L4</span> 00000000`033631c8 00000000`00000000 00007fff`789e5bc0 00000000`033631d8 00000000`00000001 00000000`033631f0 0:000> <span style='color: blue; font-weight: bold'>!do 00000000`033631f0</span> Name: ConsoleApplication1.MyType MethodTable: 00007fff789e5b30 EEClass: 00007fff789e2610 Size: 32(0x20) bytes File: C:\temp\ConsoleApplication1\bin\x64\Debug\ConsoleApplication1.exe Fields: MT Field Offset Type VT Attr Value Name 00007fffd43985a0 4000001 8 System.Int32 1 instance 255 test 00007fffd43985a0 4000002 c System.Int32 1 instance 238 test2 00007fffd43985a0 4000003 10 System.Int32 1 instance 221 test3 // 요소가 2개인 배열 0:000> <span style='color: blue; font-weight: bold'>dq 0000000003363210-8 L5</span> 00000000`03363208 00000000`00000000 00007fff`789e5bc0 00000000`03363218 00000000`00000002 00000000`03363238 00000000`03363228 00000000`03363258 </pre> <br /> 따라서, x64 환경에서의 .NET Array는 다음과 같은 구조를 갖습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > -8 : OBJECT HEADER(예: SyncBlock Index를 담는 용도) +0 : MethodTable Address +8 : 배열 요소 크기 +16 ~ : 값 배열 </pre> <br /> 이로써, 그동안의 이야기를 정리해 보면 아래와 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [x86 기준] 0 크기 배열: 12 bytes 배열이 아닌 일반 참조형 개체: 12bytes [x64 기준] 0 크기 배열: 24 bytes 배열이 아닌 일반 참조형 개체: 24bytes </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1178
(왼쪽의 숫자를 입력해야 합니다.)