성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <div style='text-decoration: line-through;'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>LayoutKind 옵션에 대해</h1> <p> 재미있는 글이 하나 떴습니다. ^^<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='http://www.csharpstudy.com/network/DevNote/Article/1009'>http://www.csharpstudy.com/network/DevNote/Article/1009</a> </pre> <br /> 위의 글에서 제가 의심이 되는 것은 다음의 문구입니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> Sequential Layout은 Managed Memory에서 마샬링을 사용해 Unmanaged Memory로 옮길 때 각 필드의 순서가 Unmanaged Memory에서 유지되는 레이아웃이다. 위의 예제에서 MyStruct구조체는 [StructLayout(LayoutKind.Sequential)]을 사용하고 있는데, 이는 Managed 메모리 영역에서는 순서가 어떨지 모르지만, Unmanaged Memory로 옮겨질 때는 반드시 필드 순서대로 데이타가 옮겨진다는 것을 의미한다.<br /> </div><br /> <br /> 즉, 위의 글에 따라 LayoutKind 옵션을 정리하면 다음과 같은 식입니다.<br /> <br /> <table class="commentlist" border="2"> <tr> <th width='200px'>Layout</th> <th>관리 메모리 필드 순서 보장</th> <th>비관리 메모리 필드 순서 보장</th> </tr> <tr> <td>Auto</td> <td>X</td> <td>X</td> </tr> <tr> <td>Sequential</td> <td>X</td> <td>O</td> </tr> <tr> <td>Explicit</td> <td>O</td> <td>O</td> </tr> </table> <br /> 의심스러운 것은 Sequential인 경우 Managed에서는 다른 메모리 구조를 가지고 있다가 Unmanaged로 복사할 때 굳이 필드 정의 순서대로 변환하는 비효율적인 작업을 하느냐에 대한 것입니다.<br /> <br /> 위의 글을 보고 MSDN 도움말을 찾아봤는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > LayoutKind Enumeration ; <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.layoutkind'>https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.layoutkind</a> </pre> <br /> Explicit 옵션에 대해서 다음과 같이 설명하고 있습니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> The precise position of each member of an object in <span style='color: blue; font-weight: bold'>unmanaged memory</span> is explicitly controlled, subject to the setting of the StructLayoutAttribute.Pack field. Each member must use the FieldOffsetAttribute to indicate the position of that field within the type. </div><br /> <br /> 위의 글에 보면, unmanaged에 대한 언급은 있지만 managed에 대한 언급은 없습니다. 이렇게 되면 확실하게 결론 내리기 위해 테스트를 통해서 한번 증명을 해봐야 될 것 같습니다.<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;' > using System; using System.Runtime.InteropServices; namespace ConsoleApplication1 { [StructLayout(LayoutKind.Sequential)] class A { byte b1 = 10; int i1 = 11; byte b2 = 12; int i2 = 13; byte b3 = 14; int i3 = 15; byte b4 = 16; int i4 = 17; } [StructLayout(LayoutKind.Sequential)] class B { byte b1 = 20; byte b2 = 21; byte b3 = 22; byte b4 = 23; int i1 = 24; int i2 = 25; int i3 = 26; int i4 = 27; } class Program { static void Main(string[] args) { A var1 = new A(); B var2 = new B(); int sizeofA = Marshal.SizeOf(var1); int sizeofB = Marshal.SizeOf(var2); Console.WriteLine("Check: " + var1.ToString() + ": " + sizeofA); Console.WriteLine("Check: " + var2.ToString() + ": " + sizeofB); Console.ReadLine(); } } } </pre> <br /> ReadLine까지 실행한 다음 windbg를 이용해 managed 영역의 메모리를 검사해 보겠습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:006> <span style='color: blue; font-weight: bold'>.loadby sos clr</span> 0:000> <span style='color: blue; font-weight: bold'>!name2ee *!ConsoleApplication1.A</span> Module: 720c1000 Assembly: mscorlib.dll -------------------------------------- Module: 00b72ed4 Assembly: ConsoleApplication1.exe Token: 02000002 MethodTable: <span style='color: blue; font-weight: bold'>00b7386c</span> EEClass: 00b7136c Name: ConsoleApplication1.A 0:000> <span style='color: blue; font-weight: bold'>!dumpheap -mt 00b7386c</span> Address MT Size <span style='color: blue; font-weight: bold'>02702490</span> 00b7386c 40 Statistics: MT Count TotalSize Class Name 00b7386c 1 40 ConsoleApplication1.A Total 1 objects 0:000> <span style='color: blue; font-weight: bold'>!dumpobj 02702490</span> Name: ConsoleApplication1.A MethodTable: 00b7386c EEClass: 00b7136c Size: 40(0x28) bytes File: d:\settings\Desktop\layout_explicit\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe Fields: MT Field <span style='color: blue; font-weight: bold'>Offset</span> Type VT Attr Value Name 724d36b4 4000001 <span style='color: blue; font-weight: bold'>4</span> System.Byte 1 instance 10 b1 724d3c50 4000002 <span style='color: blue; font-weight: bold'>8</span> System.Int32 1 instance 11 i1 724d36b4 4000003 <span style='color: blue; font-weight: bold'>c</span> System.Byte 1 instance 12 b2 724d3c50 4000004 <span style='color: blue; font-weight: bold'>10</span> System.Int32 1 instance 13 i2 724d36b4 4000005 <span style='color: blue; font-weight: bold'>14</span> System.Byte 1 instance 14 b3 724d3c50 4000006 <span style='color: blue; font-weight: bold'>18</span> System.Int32 1 instance 15 i3 724d36b4 4000007 <span style='color: blue; font-weight: bold'>1c</span> System.Byte 1 instance 16 b4 724d3c50 4000008 <span style='color: blue; font-weight: bold'>20</span> System.Int32 1 instance 17 i4 </pre> <br /> 보시는 바와 같이 Sequential인 경우에도 managed 메모리에서의 필드 순서가 보장되고 있습니다. B 클래스도 마저 확인을 해볼까요?<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.B</span> Module: 720c1000 Assembly: mscorlib.dll -------------------------------------- Module: 00b72ed4 Assembly: ConsoleApplication1.exe Token: 02000003 MethodTable: <span style='color: blue; font-weight: bold'>00b73928</span> EEClass: 00b71494 Name: ConsoleApplication1.B 0:000> <span style='color: blue; font-weight: bold'>!dumpheap -mt 00b73928</span> Address MT Size <span style='color: blue; font-weight: bold'>027024b8</span> 00b73928 28 Statistics: MT Count TotalSize Class Name 00b73928 1 28 ConsoleApplication1.B Total 1 objects 0:000> <span style='color: blue; font-weight: bold'>!dumpobj 027024b8</span> Name: ConsoleApplication1.B MethodTable: 00b73928 EEClass: 00b71494 Size: 28(0x1c) bytes File: d:\settings\Desktop\layout_explicit\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe Fields: MT Field <span style='color: blue; font-weight: bold'>Offset</span> Type VT Attr Value Name 724d36b4 4000009 <span style='color: blue; font-weight: bold'>4</span> System.Byte 1 instance 20 b1 724d36b4 400000a <span style='color: blue; font-weight: bold'>5</span> System.Byte 1 instance 21 b2 724d36b4 400000b <span style='color: blue; font-weight: bold'>6</span> System.Byte 1 instance 22 b3 724d36b4 400000c <span style='color: blue; font-weight: bold'>7</span> System.Byte 1 instance 23 b4 724d3c50 400000d <span style='color: blue; font-weight: bold'>8</span> System.Int32 1 instance 24 i1 724d3c50 400000e <span style='color: blue; font-weight: bold'>c</span> System.Int32 1 instance 25 i2 724d3c50 400000f <span style='color: blue; font-weight: bold'>10</span> System.Int32 1 instance 26 i3 724d3c50 4000010 <span style='color: blue; font-weight: bold'>14</span> System.Int32 1 instance 27 i4 </pre> <br /> 역시 순서가 지켜지고 있습니다. 게다가 2가지 Offset 값에 따라 크기를 계산해 보면 A 클래스의 인스턴스는 32바이트, B 클래스의 인스턴스는 20바이트로 Console.WriteLine으로 출력했던 sizeofA, sizeofB 변수의 값과 동일합니다. 결과적으로 Sequential인 경우에도 Managed와 Unmanaged의 필드 배치가 동일하다는 것을 유추할 수 있습니다.<br /> <br /> 실제로 순서가 달라진다는 것을 확인하기 위해 A 클래스를 Auto로 바꾸면 다음과 같이 Offset 값이 뒤죽박죽으로 나오는 것을 볼 수 있습니다.<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> !dumpobj 023f2490 Name: ConsoleApplication1.A MethodTable: 0085386c EEClass: 0085136c Size: 28(0x1c) bytes File: d:\settings\Desktop\layout_explicit\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe Fields: MT Field <span style='color: blue; font-weight: bold'>Offset</span> Type VT Attr Value Name 724d36b4 4000001 <span style='color: blue; font-weight: bold'>14</span> System.Byte 1 instance 10 b1 724d3c50 4000002 <span style='color: blue; font-weight: bold'>4</span> System.Int32 1 instance 11 i1 724d36b4 4000003 <span style='color: blue; font-weight: bold'>15</span> System.Byte 1 instance 12 b2 724d3c50 4000004 <span style='color: blue; font-weight: bold'>8</span> System.Int32 1 instance 13 i2 724d36b4 4000005 <span style='color: blue; font-weight: bold'>16</span> System.Byte 1 instance 14 b3 724d3c50 4000006 <span style='color: blue; font-weight: bold'>c</span> System.Int32 1 instance 15 i3 724d36b4 4000007 <span style='color: blue; font-weight: bold'>17</span> System.Byte 1 instance 16 b4 724d3c50 4000008 <span style='color: blue; font-weight: bold'>10</span> System.Int32 1 instance 17 i4 </pre> <br /> 테스트에 따른 결론을 말하면, Sequential은 순서가 보장되지만 Offset 값은 CLR에 의해 고정됩니다. 반면 Explicit은 Sequential의 기능과 함께 Offset 값을 개발자가 제어할 수 있는 기능을 부가하는 차이점이 있을 뿐입니다.<br /> <br /> 혹시... 제가 잘못 이해하고 있거나 테스트에 뭔가 잘못된 점이 있을까요? ^^<br /> </p><br /> </div><br /> <br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1076
(왼쪽의 숫자를 입력해야 합니다.)