์์ ๋ ธ๋ค ์๊ฐ V2, ์ฐ๋ฆฌ๋ ๋๋ ธ์ด ํด์๋๋ก ์ด๋ํ๊ณ ์์ต๋๋ค. ์ด๋ ์ฐ๋ฆฌ๊ฐ ๊ด์ฌ์๋ ์ ์ฒด ์๊ฐ ๋ฒ์๋ฅผ ๋ํ ๋ด๊ธฐ ์ํด ๋ ์ด์ 8 ๋ฐ์ดํธ ์ ์๋ฅผ ์ฌ์ฉํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ด๋ก ์ธํด Noda Time์ (๋ง์) ๊ตฌ์กฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์กฐ์ฌํ๊ฒ๋์๊ณ ๊ฒฐ๊ณผ์ ์ผ๋ก ์ ๋ฅผ ์ด๋์์ต๋๋ค. CLR์ ์ ๋ ฌ ๊ฒฐ์ ์์ ์ฝ๊ฐ์ ์ด์ํ ์ ์ ๋ฐ๊ฒฌํ์ต๋๋ค.
์ฒซ์งธ, ๋๋ ์ด๊ฒ์ด ์คํ ์ด๋ค ๊ธฐ๋ณธ ๋์์ ์ธ์ ๋ ์ง ๋ณ๊ฒฝ ๋ ์ ์์ต๋๋ค ๊ตฌํ ๊ฒฐ์ ํ๊ณ ์๋ค. ๋๋ ๊ฒ์ ๊นจ๋ซ๊ฒ ์ ์ฌ์ฉํ์ฌ ์์ [StructLayout]
ํ๊ณ [FieldOffset]
,ํ์ง๋ง ๋ ์คํ๋ ค ๊ฐ๋ฅํ๋ฉด์ด ํ์ํ์ง ์์ ์๋ฃจ์
์ ๊ฐ์ง๊ณ ์ฌ ๊ฒ์
๋๋ค.
๋ด ํต์ฌ ์๋๋ฆฌ์ค๋ struct
์ฐธ์กฐ ์ ํ ํ๋์ ๋ ๊ฐ์ ๋ค๋ฅธ ๊ฐ ์ ํ ํ๋๋ฅผ ํฌํจํ๋์ด ํ๋์ ๋ํ ๊ฐ๋จํ ๋ํผ์
๋๋ค int
. ๋๋ ๊ทธ๊ฒ์ด 64 ๋นํธ CLR์์ 16 ๋ฐ์ดํธ๋ก ํํ ๋๊ธฐ๋ฅผ ๋ฐ๋ ์ง๋ง (์ฐธ์กฐ ์ฉ์ผ๋ก 8 ๋ฐ์ดํธ, ๋๋จธ์ง ์ฉ์ผ๋ก 4 ๋ฐ์ดํธ) ์ด๋ค ์ด์ ๋ก 24 ๋ฐ์ดํธ๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฐ๋ฐ ์ ๋ ๋ฐฐ์ด์ ์ฌ์ฉํ์ฌ ๊ณต๊ฐ์ ์ธก์ ํ๊ณ ์์ต๋๋ค. ์ํฉ์ ๋ฐ๋ผ ๋ ์ด์์์ด ๋ค๋ฅผ ์ ์๋ค๋ ๊ฒ์ ์ดํดํ์ง๋ง ์ด๊ฒ์ ํฉ๋ฆฌ์ ์ธ ์์์ ์ฒ๋ผ ๋๊ปด์ก์ต๋๋ค.
๋ค์์ ๋ฌธ์ ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ํ ํ๋ก๊ทธ๋จ์ ๋๋ค.
using System;
using System.Runtime.InteropServices;
#pragma warning disable 0169
struct Int32Wrapper
{
int x;
}
struct TwoInt32s
{
int x, y;
}
struct TwoInt32Wrappers
{
Int32Wrapper x, y;
}
struct RefAndTwoInt32s
{
string text;
int x, y;
}
struct RefAndTwoInt32Wrappers
{
string text;
Int32Wrapper x, y;
}
class Test
{
static void Main()
{
Console.WriteLine("Environment: CLR {0} on {1} ({2})",
Environment.Version,
Environment.OSVersion,
Environment.Is64BitProcess ? "64 bit" : "32 bit");
ShowSize<Int32Wrapper>();
ShowSize<TwoInt32s>();
ShowSize<TwoInt32Wrappers>();
ShowSize<RefAndTwoInt32s>();
ShowSize<RefAndTwoInt32Wrappers>();
}
static void ShowSize<T>()
{
long before = GC.GetTotalMemory(true);
T[] array = new T[100000];
long after = GC.GetTotalMemory(true);
Console.WriteLine("{0}: {1}", typeof(T),
(after - before) / array.Length);
}
}
๊ทธ๋ฆฌ๊ณ ๋ด ๋ฉํฑ์ ์ปดํ์ผ ๋ฐ ์ถ๋ ฅ :
c:\Users\Jon\Test>csc /debug- /o+ ShowMemory.cs
Microsoft (R) Visual C# Compiler version 12.0.30501.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reserved.
c:\Users\Jon\Test>ShowMemory.exe
Environment: CLR 4.0.30319.34014 on Microsoft Windows NT 6.2.9200.0 (64 bit)
Int32Wrapper: 4
TwoInt32s: 8
TwoInt32Wrappers: 8
RefAndTwoInt32s: 16
RefAndTwoInt32Wrappers: 24
๊ทธ๋์:
- ์ฐธ์กฐ ์ ํ ํ๋๊ฐ์๋ ๊ฒฝ์ฐ CLR์
Int32Wrapper
ํ๋๋ฅผ ํจ๊ป ์์ถ ํ ์ ์์ต๋๋ค (TwoInt32Wrappers
ํฌ๊ธฐ๋ 8). - ์ฐธ์กฐ ์ ํ ํ๋๊ฐ ์์ด๋ CLR์ ์ฌ์ ํ
int
ํ๋๋ฅผ ํจ๊ป ์์ถ ํ ์ ์์ต๋๋ค (RefAndTwoInt32s
ํฌ๊ธฐ๋ 16). - ๋ ๊ฐ์ง๋ฅผ ๊ฒฐํฉํ๋ฉด ๊ฐ
Int32Wrapper
ํ๋๊ฐ 8 ๋ฐ์ดํธ๋ก ์ฑ์์ง๊ฑฐ๋ ์ ๋ ฌ ๋ ๊ฒ์ฒ๋ผ ๋ณด์ ๋๋ค. (RefAndTwoInt32Wrappers
ํฌ๊ธฐ๋ 24์ ๋๋ค.) - ๋๋ฒ๊ฑฐ์์ ๋์ผํ ์ฝ๋๋ฅผ ์คํํ๋ฉด (ํ์ง๋ง ์ฌ์ ํ ๋ฆด๋ฆฌ์ค ๋น๋) ํฌ๊ธฐ๊ฐ 12๋ก ํ์๋ฉ๋๋ค.
๋ช ๊ฐ์ง ๋ค๋ฅธ ์คํ์์๋ ๋น์ทํ ๊ฒฐ๊ณผ๊ฐ ๋์์ต๋๋ค.
- ๊ฐ ์ ํ ํ๋ ๋ค์ ์ฐธ์กฐ ์ ํ ํ๋๋ฅผ ๋๋ ๊ฒ์ ๋์์ด๋์ง ์์ต๋๋ค.
object
๋์ ์ฌ์ฉ ํ๋string
๊ฒ์ ๋์ ์ด ๋์ง ์์ต๋๋ค ( โ๋ชจ๋ ์ฐธ์กฐ ์ ํโ์ผ ๊ฒ์ผ๋ก ์์).- ์ฐธ์กฐ ์ฃผ์์ โ๋ํผโ๋ก ๋ค๋ฅธ ๊ตฌ์กฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋์์ด๋์ง ์์ต๋๋ค.
- ์ฐธ์กฐ ์ฃผ์์ ๋ํผ๋ก ์ผ๋ฐ ๊ตฌ์กฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋์์ด๋์ง ์์ต๋๋ค.
- ํ๋๋ฅผ ๊ณ์ ์ถ๊ฐํ๋ฉด (๋จ์์ฑ์ ์ํด ์์ผ๋ก)
int
ํ๋๋ ์ฌ์ ํ 4 ๋ฐ์ดํธ๋กInt32Wrapper
๊ณ์ฐ ๋๊ณ ํ๋๋ 8 ๋ฐ์ดํธ๋ก ๊ณ์ฐ๋ฉ๋๋ค. [StructLayout(LayoutKind.Sequential, Pack = 4)]
์์ผ์์๋ ๋ชจ๋ ๊ตฌ์กฐ์ฒด์ ์ถ๊ฐํด๋ ๊ฒฐ๊ณผ๊ฐ ๋ณ๊ฒฝ๋์ง๋ ์์ต๋๋ค.
๋๊ตฌ๋ ์ง ์ด์ ๋ํ ์ค๋ช (์ด์์ ์ผ๋ก๋ ์ฐธ์กฐ ๋ฌธ์ ํฌํจ)์ด ์๊ฑฐ๋ ์์ ํ๋ ์คํ์ ์ ์ง์ ํ์ง ์๊ณ ํ๋๋ฅผ ์์ถํ๊ณ ์ถ๋ค๋ CLR์ ๋ํ ํํธ๋ฅผ ์ป์ ์์๋ ๋ฐฉ๋ฒ์ ๋ํ ์ ์์ด ์์ต๋๊น?
๋ต๋ณ
๋๋ ์ด๊ฒ์ด ๋ฒ๊ทธ๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์๋ ๋ ์ด์์์ ๋ถ์์ฉ์ด ์์ต๋๋ค. 64 ๋นํธ ๋ชจ๋์์ 8 ๋ฐ์ดํธ์ ๋ฐฐ์ ์ธ ์ฃผ์์ ์ค์ํ์ง ์์ ํ๋๋ฅผ ์ ๋ ฌํ๋ ๊ฒ์ ์ข์ํฉ๋๋ค. [StructLayout(LayoutKind.Sequential)]
์์ฑ ์ ๋ช
์ ์ ์ผ๋ก ์ ์ฉํ ๊ฒฝ์ฐ์๋ ๋ฐ์ ํฉ๋๋ค. ๊ทธ๊ฒ์ ์ผ์ด๋์ง ์์์ผํฉ๋๋ค.
๊ตฌ์กฐ์ฒด ๋ฉค๋ฒ๋ฅผ ๊ณต๊ฐํ๊ณ ๋ค์๊ณผ ๊ฐ์ด ํ ์คํธ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ฌ ํ์ธํ ์ ์์ต๋๋ค.
var test = new RefAndTwoInt32Wrappers();
test.text = "adsf";
test.x.x = 0x11111111;
test.y.x = 0x22222222;
Console.ReadLine(); // <=== Breakpoint here
์ค๋จ ์ ์ ๋๋ฌํ๋ฉด Debug + Windows + Memory + Memory 1์ ์ฌ์ฉํฉ๋๋ค. 4 ๋ฐ์ดํธ ์ ์๋ก ์ ํ &test
ํ๊ณ Address ํ๋์ ์
๋ ฅํฉ๋๋ค.
0x000000E928B5DE98 0ed750e0 000000e9 11111111 00000000 22222222 00000000
0xe90ed750e0
๋ด ์ปดํจํฐ์ ๋ฌธ์์ด ํฌ์ธํฐ์
๋๋ค (๋น์ ์ ๊ฒ์ด ์๋๋๋ค). ์ฝ๊ฒ ๋ณผ ์ ์์ต๋๋คInt32Wrappers
ํฌ๊ธฐ๋ฅผ 24 ๋ฐ์ดํธ๋ก ๋ฐ๊พธ๋ ์ถ๊ฐ 4 ๋ฐ์ดํธ์ ํจ๋ฉ์ผ๋ก์ . ๊ตฌ์กฐ์ฒด๋ก ๋์๊ฐ์ ๋ฌธ์์ด์ ๋ง์ง๋ง์ ๋ฃ์ผ์ญ์์ค. ๋ฐ๋ณตํ๋ฉด ๋ฌธ์์ด ํฌ์ธํฐ๊ฐ ์ฌ์ ํ ์ฒซ ๋ฒ์งธ ์์ ์ ์ ์์ต๋๋ค . ์๋ฐ LayoutKind.Sequential
, ๋น์ ์ LayoutKind.Auto
.
๋ง์ดํฌ๋ก ์ํํธ๊ฐ์ด ๋ฌธ์ ๋ฅผ ๊ณ ์น๋๋ก ์ค๋ํ๋ ๊ฒ์ ์ด๋ ค์ธ ๊ฒ์
๋๋ค. ๋๋ฌด ์ค๋ซ๋์ ์ด๋ฐ ์์ผ๋ก ์๋ํ๊ธฐ ๋๋ฌธ์ ์ด๋ค ๋ณํ๋ ๊นจ์ง ๊ฒ์
๋๋ค. ๋ฌด์ธ๊ฐ๋ฅผ ๋จ๋ฆฌ๊ฒ ๊ฒ ์
๋๋ค. CLR [StructLayout]
์ struct์ ๊ด๋ฆฌ ๋ฒ์ ์ ์กด์ค ํ๊ณ blittable๋ก ๋ง๋ค ๋ ค๊ณ ์๋ ํ ๋ฟ์ด๋ฉฐ ์ผ๋ฐ์ ์ผ๋ก ๋น ๋ฅด๊ฒ ํฌ๊ธฐํฉ๋๋ค. DateTime์ ํฌํจํ๋ ๋ชจ๋ ๊ตฌ์กฐ์ฒด์ ๋ํด ์ ๋ช
ํฉ๋๋ค. ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง์ฌ๋ง ํ ๋๋ง ์ง์ ํ LayoutKind ๋ณด์ฅ์๋ฐ์ต๋๋ค. ๋ง์ฌ๋ง ๋ ๋ฒ์ ์ ํ์คํ 16 ๋ฐ์ดํธ Marshal.SizeOf()
์
๋๋ค.
LayoutKind.Explicit
๋น์ ์ด ๋ฃ๊ณ ์ถ์๋ ๊ฒ์ด ์๋๋ผ ๊ทธ๊ฒ์ ๊ณ ์ณ ์ฌ์ฉ ํ์ญ์์ค.
๋ต๋ณ
EDIT2
struct RefAndTwoInt32Wrappers
{
public int x;
public string s;
}
์ด ์ฝ๋๋ 8 ๋ฐ์ดํธ๋ก ์ ๋ ฌ๋๋ฏ๋ก ๊ตฌ์กฐ์ฒด๋ 16 ๋ฐ์ดํธ๋ฅผ ๊ฐ๊ฒ๋ฉ๋๋ค. ๋น๊ตํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
struct RefAndTwoInt32Wrappers
{
public int x,y;
public string s;
}
4 ๋ฐ์ดํธ๋ก ์ ๋ ฌ๋๋ฏ๋ก์ด ๊ตฌ์กฐ์ฒด๋ 16 ๋ฐ์ดํธ๋ฅผ ๊ฐ๊ฒ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ฌ๊ธฐ์ ์ด๋ก ์ ๊ทผ๊ฑฐ๋ CLR์ ๊ตฌ์กฐ์ฒด ๊ฒฐํฉ์ด ๊ฐ์ฅ ๋ง์ด ์ ๋ ฌ ๋ ํ๋์ ์์ ์ํด ๊ฒฐ์ ๋๋ค๋ ๊ฒ์ ๋๋ค. clases๋ ๋ถ๋ช ํ ๊ทธ๋ ๊ฒ ํ ์ ์์ผ๋ฏ๋ก 8 ๋ฐ์ดํธ ์ ๋ ฌ ์ํ๋ก ์ ์ง๋ฉ๋๋ค.
์ด์ ๋ชจ๋ ๊ฒ์ ๊ฒฐํฉํ๊ณ ๊ตฌ์กฐ์ฒด๋ฅผ ์์ฑํ๋ฉด :
struct RefAndTwoInt32Wrappers
{
public int x,y;
public Int32Wrapper z;
public string s;
}
24 ๋ฐ์ดํธ {x, y}๋ ๊ฐ๊ฐ 4 ๋ฐ์ดํธ, {z, s}๋ 8 ๋ฐ์ดํธ์ ๋๋ค. ๊ตฌ์กฐ์ฒด์ ref ์ ํ์ ๋์ ํ๋ฉด CLR์ ํญ์ ์ฌ์ฉ์ ์ง์ ๊ตฌ์กฐ์ฒด๋ฅผ ํด๋์ค ์ ๋ ฌ๊ณผ ์ผ์นํ๋๋ก ์ ๋ ฌํฉ๋๋ค.
struct RefAndTwoInt32Wrappers
{
public Int32Wrapper z;
public long l;
public int x,y;
}
Int32Wrapper๋ ๊ธธ์ด์ ๋์ผํ๊ฒ ์ ๋ ฌ๋๋ฏ๋ก์ด ์ฝ๋๋ 24 ๋ฐ์ดํธ๋ฅผ ๊ฐ๊ฒ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ฌ์ฉ์ ์ง์ ๊ตฌ์กฐ์ฒด ๋ํผ๋ ํญ์ ๊ตฌ์กฐ์์ ๊ฐ์ฅ ๋์ / ๊ฐ์ฅ ์ ๋ ฌ ๋ ํ๋ ๋๋ ์์ฒด ๋ด๋ถ ๊ฐ์ฅ ์ค์ํ ํ๋์ ์ ๋ ฌ๋ฉ๋๋ค. ๋ฐ๋ผ์ 8 ๋ฐ์ดํธ ์ ๋ ฌ ๋ ์ฐธ์กฐ ๋ฌธ์์ด์ ๊ฒฝ์ฐ ๊ตฌ์กฐ์ฒด ๋ํผ๊ฐ ์ด์ ์ ๋ ฌ๋ฉ๋๋ค.
๊ตฌ์กฐ์ฒด ๋ด๋ถ์ ์ต์ข ์ฌ์ฉ์ ์ง์ ๊ตฌ์กฐ์ฒด ํ๋๋ ํญ์ ๊ตฌ์กฐ์ฒด์์ ๊ฐ์ฅ ๋๊ฒ ์ ๋ ฌ ๋ ์ธ์คํด์ค ํ๋์ ์ ๋ ฌ๋ฉ๋๋ค. ์ด์ ์ด๊ฒ์ด ๋ฒ๊ทธ์ธ์ง ํ์คํ์ง ์์ง๋ง ์ฆ๊ฑฐ๊ฐ ์์ผ๋ฉด ์ด๊ฒ์ด ์์์ ์ธ ๊ฒฐ์ ์ผ ์ ์๋ค๋ ๋ด ์๊ฒฌ์ ๊ณ ์ ํ ๊ฒ์ ๋๋ค.
ํธ์งํ๋ค
ํฌ๊ธฐ๋ ์ค์ ๋ก ํ์ ํ ๋น ๋ ๊ฒฝ์ฐ์๋ง ์ ํํ์ง๋ง ๊ตฌ์กฐ์ฒด ์์ฒด์ ํฌ๊ธฐ๋ ๋ ์์ต๋๋ค (ํ๋์ ์ ํํ ํฌ๊ธฐ). ์ถ๊ฐ ๋ถ์์ ํตํด ์ด๊ฒ์ด CLR ์ฝ๋์ ๋ฒ๊ทธ ์ผ ์ ์์ง๋ง ์ฆ๊ฑฐ๋ก ๋ฐฑ์ ํด์ผ ํจ์ ์ ์ํฉ๋๋ค.
๋๋ cli ์ฝ๋๋ฅผ ๊ฒ์ฌํ๊ณ ์ ์ฉํ ๊ฒ์ด ๋ฐ๊ฒฌ๋๋ฉด ์ถ๊ฐ ์ ๋ฐ์ดํธ๋ฅผ ๊ฒ์ ํ ๊ฒ์ ๋๋ค.
์ด๊ฒ์ .NET mem ํ ๋น ์์์ ์ฌ์ฉํ๋ ์ ๋ ฌ ์ ๋ต์ ๋๋ค.
public static RefAndTwoInt32s[] test = new RefAndTwoInt32s[1];
static void Main()
{
test[0].text = "a";
test[0].x = 1;
test[0].x = 1;
Console.ReadKey();
}
x64์์ .net40์ผ๋ก ์ปดํ์ผ ๋์ด ์ฝ๋๋ WinDbg์์ ๋ค์์ ์ํ ํ ์ ์์ต๋๋ค.
๋จผ์ ํ์์ ์ ํ์ ์ฐพ์ ์ ์์ต๋๋ค.
0:004> !dumpheap -type Ref
Address MT Size
0000000003e72c78 000007fe61e8fb58 56
0000000003e72d08 000007fe039d3b78 40
Statistics:
MT Count TotalSize Class Name
000007fe039d3b78 1 40 RefAndTwoInt32s[]
000007fe61e8fb58 1 56 System.Reflection.RuntimeAssembly
Total 2 objects
์ผ๋จ ์ฐ๋ฆฌ๊ฐ ๊ทธ ์ฃผ์ ์๋์ ๋ฌด์์ด ์๋์ง ๋ณผ ์ ์์ต๋๋ค.
0:004> !do 0000000003e72d08
Name: RefAndTwoInt32s[]
MethodTable: 000007fe039d3b78
EEClass: 000007fe039d3ad0
Size: 40(0x28) bytes
Array: Rank 1, Number of elements 1, Type VALUETYPE
Fields:
None
์ด๊ฒ์ด ValueType์ด๊ณ ์ฐ๋ฆฌ๊ฐ ์์ฑ ํ ๊ฒ์์ ์ ์ ์์ต๋๋ค. ์ด๊ฒ์ด ๋ฐฐ์ด์ด๊ธฐ ๋๋ฌธ์ ๋ฐฐ์ด์์๋ ๋จ์ผ ์์์ ValueType def๋ฅผ ๊ฐ์ ธ์์ผํฉ๋๋ค.
0:004> !dumparray -details 0000000003e72d08
Name: RefAndTwoInt32s[]
MethodTable: 000007fe039d3b78
EEClass: 000007fe039d3ad0
Size: 40(0x28) bytes
Array: Rank 1, Number of elements 1, Type VALUETYPE
Element Methodtable: 000007fe039d3a58
[0] 0000000003e72d18
Name: RefAndTwoInt32s
MethodTable: 000007fe039d3a58
EEClass: 000007fe03ae2338
Size: 32(0x20) bytes
File: C:\ConsoleApplication8\bin\Release\ConsoleApplication8.exe
Fields:
MT Field Offset Type VT Attr Value Name
000007fe61e8c358 4000006 0 System.String 0 instance 0000000003e72d30 text
000007fe61e8f108 4000007 8 System.Int32 1 instance 1 x
000007fe61e8f108 4000008 c System.Int32 1 instance 0 y
16 ๋ฐ์ดํธ๊ฐ ํจ๋ฉ ์ฉ์ผ๋ก ์์ฝ๋์ด ์์ผ๋ฏ๋ก ๊ตฌ์กฐ๋ ์ค์ ๋ก 32 ๋ฐ์ดํธ์ด๋ฏ๋ก ์ค์ ๋ก ๋ชจ๋ ๊ตฌ์กฐ๋ ์ฒ์๋ถํฐ ์ต์ 16 ๋ฐ์ดํธ ํฌ๊ธฐ์ ๋๋ค.
int์ ๋ฌธ์์ด ์ฐธ์กฐ์์ 16 ๋ฐ์ดํธ๋ฅผ ์ถ๊ฐํ๋ฉด 0000000003e72d18 + 8 ๋ฐ์ดํธ EE / ํจ๋ฉ์ด๋ฉ๋๋ค. 0000000003e72d30์ด๋๊ณ ์ด๊ฒ์ ๋ฌธ์์ด ์ฐธ์กฐ์ ์์ ์ง์ ์ด๋ฉฐ ๋ชจ๋ ์ฐธ์กฐ๋ ์ฒซ ๋ฒ์งธ ์ค์ ๋ฐ์ดํฐ ํ๋์์ 8 ๋ฐ์ดํธ๊ฐ ์ฑ์ ์ง๋ฏ๋ก ์ด๊ฒ์์ด ๊ตฌ์กฐ์ 32 ๋ฐ์ดํธ๋ฅผ ์ฐจ์งํฉ๋๋ค.
๋ฌธ์์ด์ด ์ค์ ๋ก ๊ทธ๋ ๊ฒ ์ฑ์์ ธ ์๋์ง ์ดํด ๋ณด๊ฒ ์ต๋๋ค.
0:004> !do 0000000003e72d30
Name: System.String
MethodTable: 000007fe61e8c358
EEClass: 000007fe617f3720
Size: 28(0x1c) bytes
File: C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: a
Fields:
MT Field Offset Type VT Attr Value Name
000007fe61e8f108 40000aa 8 System.Int32 1 instance 1 m_stringLength
000007fe61e8d640 40000ab c System.Char 1 instance 61 m_firstChar
000007fe61e8c358 40000ac 18 System.String 0 shared static Empty
>> Domain:Value 0000000001577e90:NotInit <<
์ด์ ์์ ํ๋ก๊ทธ๋จ์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ถ์ํด ๋ณด๊ฒ ์ต๋๋ค.
public static RefAndTwoInt32Wrappers[] test = new RefAndTwoInt32Wrappers[1];
static void Main()
{
test[0].text = "a";
test[0].x.x = 1;
test[0].y.x = 1;
Console.ReadKey();
}
0:004> !dumpheap -type Ref
Address MT Size
0000000003c22c78 000007fe61e8fb58 56
0000000003c22d08 000007fe039d3c00 48
Statistics:
MT Count TotalSize Class Name
000007fe039d3c00 1 48 RefAndTwoInt32Wrappers[]
000007fe61e8fb58 1 56 System.Reflection.RuntimeAssembly
Total 2 objects
์ด์ ๊ตฌ์กฐ์ฒด๋ 48 ๋ฐ์ดํธ์ ๋๋ค.
0:004> !dumparray -details 0000000003c22d08
Name: RefAndTwoInt32Wrappers[]
MethodTable: 000007fe039d3c00
EEClass: 000007fe039d3b58
Size: 48(0x30) bytes
Array: Rank 1, Number of elements 1, Type VALUETYPE
Element Methodtable: 000007fe039d3ae0
[0] 0000000003c22d18
Name: RefAndTwoInt32Wrappers
MethodTable: 000007fe039d3ae0
EEClass: 000007fe03ae2338
Size: 40(0x28) bytes
File: C:\ConsoleApplication8\bin\Release\ConsoleApplication8.exe
Fields:
MT Field Offset Type VT Attr Value Name
000007fe61e8c358 4000009 0 System.String 0 instance 0000000003c22d38 text
000007fe039d3a20 400000a 8 Int32Wrapper 1 instance 0000000003c22d20 x
000007fe039d3a20 400000b 10 Int32Wrapper 1 instance 0000000003c22d28 y
์ฌ๊ธฐ์ ์ํฉ์ ๋์ผํฉ๋๋ค. 0000000003c22d18 + 8 ๋ฐ์ดํธ์ ๋ฌธ์์ด ์ฐธ์กฐ๋ฅผ ์ถ๊ฐํ๋ฉด ๊ฐ์ด ์ค์ ๋ก ์ฐ๋ฆฌ๊ฐ์๋ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํค๋ ์ฒซ ๋ฒ์งธ Int ๋ํผ์ ์์ ๋ถ๋ถ์์ ๋๋ฉ๋๋ค.
์ด์ ๊ฐ ๊ฐ์ด ๊ฐ์ฒด ์ฐธ์กฐ์์ ๋ค์ ํ์ธํ ์ ์์ต๋๋ค. 0000000003c22d20์ ์ดํด๋ณด๋ฉด์ ํ์ธํ ์ ์์ต๋๋ค.
0:004> !do 0000000003c22d20
<Note: this object has an invalid CLASS field>
Invalid object
์ค์ ๋ก ๊ทธ๊ฒ์ด obj ๋๋ vt์ด๋ฉด ์ฃผ์๊ฐ ์ฐ๋ฆฌ์๊ฒ ์๋ฌด๊ฒ๋ ์๋ ค์ฃผ์ง ์๋ ๊ตฌ์กฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ ์ ํํฉ๋๋ค.
0:004> !dumpvc 000007fe039d3a20 0000000003c22d20
Name: Int32Wrapper
MethodTable: 000007fe039d3a20
EEClass: 000007fe03ae23c8
Size: 24(0x18) bytes
File: C:\ConsoleApplication8\bin\Release\ConsoleApplication8.exe
Fields:
MT Field Offset Type VT Attr Value Name
000007fe61e8f108 4000001 0 System.Int32 1 instance 1 x
๋ฐ๋ผ์ ์ค์ ๋ก ์ด๊ฒ์ ์ด๋ฒ์ 8 ๋ฐ์ดํธ ์ ๋ ฌ๋๋ Union ์ ํ๊ณผ ๋ ๋น์ทํฉ๋๋ค (๋ชจ๋ ํจ๋ฉ์ ๋ถ๋ชจ ๊ตฌ์กฐ์ฒด์ ์ ๋ ฌ ๋จ). ๊ทธ๋ ์ง ์๋ค๋ฉด 20 ๋ฐ์ดํธ๋ก ๋๋ ๊ฒ์ด๊ณ ๊ทธ๊ฒ์ ์ต์ ์ด ์๋๋ฏ๋ก mem ํ ๋น์๋ ๊ฒฐ์ฝ ๊ทธ๊ฒ์ ํ์ฉํ์ง ์์ ๊ฒ์ ๋๋ค. ๋ค์ ์ํ์ํ๋ฉด ๊ตฌ์กฐ์ฒด์ ํฌ๊ธฐ๊ฐ ์ค์ ๋ก 40 ๋ฐ์ดํธ์์ ์ ์ ์์ต๋๋ค.
๋ฐ๋ผ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ข ๋ ๋ณด์์ ์ผ๋ก ์ฌ์ฉํ๋ ค๋ฉด ๊ตฌ์กฐ์ฒด ์ฌ์ฉ์ ์ง์ ๊ตฌ์กฐ์ฒด ํ์์ผ๋ก ์์ถํ์ง ๋ง๊ณ ๋์ ๊ฐ๋จํ ๋ฐฐ์ด์ ์ฌ์ฉํ์ญ์์ค. ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ํ (์ : VirtualAllocEx)์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๋ ๊ฒ์ ๋๋ค. ์ด๋ ๊ฒํ๋ฉด ๊ณ ์ ํ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก์ด ์ ๊ณต๋๊ณ ์ํ๋ ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌ ํ ์ โโ์์ต๋๋ค.
์ฌ๊ธฐ์ ๋ง์ง๋ง ์ง๋ฌธ์ ์ ๊ฐ์๊ธฐ ์ฐ๋ฆฌ๊ฐ ๊ทธ๋ฐ ๋ ์ด์์์ ์ป์ ์ ์๋์ง์ ๋๋ค. int [] ์ฆ๋ถ์ ์ง ํฐ๋ ์ฝ๋์ ์ฑ๋ฅ์ struct []์ ์นด์ดํฐ ํ๋ ์ฆ๋ถ๊ณผ ๋น๊ตํ๋ฉด ๋ ๋ฒ์งธ๋ ์ ๋์จ์ด๋๋ 8 ๋ฐ์ดํธ ์ ๋ ฌ ์ฃผ์๋ฅผ ์์ฑํ์ง๋ง ์งํ ํ๋ฉด ๋ ์ต์ ํ ๋ ์ด์ ๋ธ๋ฆฌ ์ฝ๋๋ก ๋ณํ๋ฉ๋๋ค (๋จ์ผ LEA ๋ ๋ค์ค MOV). ๊ทธ๋ฌ๋ ์ฌ๊ธฐ์ ์ค๋ช ๋ ๊ฒฝ์ฐ ์ฑ๋ฅ์ด ์ค์ ๋ก ๋ ๋๋น ์ง ๊ฒ์ด๋ฏ๋ก ์ฌ๋ฌ ํ๋๋ฅผ ๊ฐ์ง ์์๋ ์ฌ์ฉ์ ์ง์ ํ์์ด๋ฏ๋ก ๊ธฐ๋ณธ CLR ๊ตฌํ๊ณผ ์ผ์นํ๋ฏ๋ก ์์ ์ฃผ์ ๋์ ์์ ์ฃผ์๋ฅผ ์ ๋ ฅํ๋ ๊ฒ์ด ๋ ์ฌ์ธ ์ ์์ต๋๋ค. value (๋ถ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์) ๊ทธ๋ฆฌ๊ณ ๊ฑฐ๊ธฐ์์ ๊ตฌ์กฐ์ฒด ํจ๋ฉ์ ์ํํ์ฌ ๋ ํฐ ๋ฐ์ดํธ ํฌ๊ธฐ๋ฅผ ๋ง๋ญ๋๋ค.
๋ต๋ณ
์์ฝ์ ์๋ง๋ ์์ @Hans Passant์ ๋ต๋ณ์ ์ฐธ์กฐํ์ญ์์ค. Layout Sequential์ด ์๋ํ์ง ์์ต๋๋ค.
์ผ๋ถ ํ ์คํธ :
๊ทธ๊ฒ์ ํ์คํ 64 ๋นํธ์๋ง ์๊ณ ๊ฐ์ฒด ์ฐธ์กฐ๋ ๊ตฌ์กฐ์ฒด๋ฅผ โ๋ โ์ํต๋๋ค. 32 ๋นํธ๋ ๋น์ ์ด ๊ธฐ๋ํ๋ ๊ฒ์ํฉ๋๋ค :
Environment: CLR 4.0.30319.34209 on Microsoft Windows NT 6.2.9200.0 (32 bit)
ConsoleApplication1.Int32Wrapper: 4
ConsoleApplication1.TwoInt32s: 8
ConsoleApplication1.TwoInt32Wrappers: 8
ConsoleApplication1.ThreeInt32Wrappers: 12
ConsoleApplication1.Ref: 4
ConsoleApplication1.RefAndTwoInt32s: 12
ConsoleApplication1.RefAndTwoInt32Wrappers: 12
ConsoleApplication1.RefAndThreeInt32s: 16
ConsoleApplication1.RefAndThreeInt32Wrappers: 16
๊ฐ์ฒด ์ฐธ์กฐ๊ฐ ์ถ๊ฐ ๋ ์๋ง์ ๋ชจ๋ ๊ตฌ์กฐ์ฒด๋ 4 ๋ฐ์ดํธ ํฌ๊ธฐ๊ฐ ์๋ 8 ๋ฐ์ดํธ๋ก ํ์ฅ๋ฉ๋๋ค. ํ ์คํธ ํ์ฅ :
Environment: CLR 4.0.30319.34209 on Microsoft Windows NT 6.2.9200.0 (64 bit)
ConsoleApplication1.Int32Wrapper: 4
ConsoleApplication1.TwoInt32s: 8
ConsoleApplication1.TwoInt32Wrappers: 8
ConsoleApplication1.ThreeInt32Wrappers: 12
ConsoleApplication1.Ref: 8
ConsoleApplication1.RefAndTwoInt32s: 16
ConsoleApplication1.RefAndTwoInt32sSequential: 16
ConsoleApplication1.RefAndTwoInt32Wrappers: 24
ConsoleApplication1.RefAndThreeInt32s: 24
ConsoleApplication1.RefAndThreeInt32Wrappers: 32
ConsoleApplication1.RefAndFourInt32s: 24
ConsoleApplication1.RefAndFourInt32Wrappers: 40
์ฐธ์กฐ๊ฐ ์ถ๊ฐ ๋ ์๋ง์ ๋ชจ๋ Int32Wrapper๊ฐ 8 ๋ฐ์ดํธ๊ฐ๋๋ฏ๋ก ๋จ์ํ ์ ๋ ฌ์ด ์๋๋๋ค. LoH ํ ๋น์ด ๋ค๋ฅด๊ฒ ์ ๋ ฌ ๋ ๊ฒฝ์ฐ ๋ฐฐ์ด ํ ๋น์ ์ค์์ต๋๋ค.
๋ต๋ณ
๋ฏน์ค์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ๊ธฐ ์ํด ๋ณด์ ํ ์ ํ์์ ํ๋ ์ด์์ ์ ํ์ ๋ง๋ค์์ต๋๋ค.
struct RefAndTwoInt32Wrappers2
{
string text;
TwoInt32Wrappers z;
}
ํ๋ก๊ทธ๋จ์ ๋ค์์ ๊ธฐ๋กํฉ๋๋ค.
RefAndTwoInt32Wrappers2: 16
๋ฐ๋ผ์ TwoInt32Wrappers
๊ตฌ์กฐ์ฒด๊ฐ ์ RefAndTwoInt32Wrappers2
๊ตฌ์กฐ์ฒด ์์ ์ ๋๋ก ์ ๋ ฌ ๋ ๊ฒ์ฒ๋ผ ๋ณด์
๋๋ค .