C# - 구조체의 크기가 16바이트가 넘어가면 힙에 할당된다?
아래와 같은 질문에서,
시작하세요 C# 9.0, 225페이지 구조체 관련 질문드립니다.
; https://www.sysnet.pe.kr/3/0/5489
구조체의 크기가 16바이트를 넘어가면 힙에 할당된다고... 하는데... 아니... 도대체 그런 근거 없는 사실을 퍼뜨리고 있는 사람이 누굴까요? ^^;
구조체는 크기가 어떻게 되었든 무조건 스택에 할당됩니다. 그래도, 말로만 하면 재미가 없으니 눈으로 확인할 수 있도록 테스트를 해봐야겠지요. ^^ 방법은, 다음과 같이 매우 간단합니다.
using System;
using System.Threading;
public struct Size64
{
public long l1;
public long l2;
public long l3;
public long l4;
public long l5;
public long l6;
public long l7;
public long l8;
}
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(threadFunc);
t.IsBackground = true;
t.Start();
while (true)
{
int n = GC.CollectionCount(0) + GC.CollectionCount(1) + GC.CollectionCount(2);
Console.WriteLine(n);
Thread.Sleep(1000);
}
}
private static void threadFunc()
{
while (true)
{
Size64 variable = new Size64();
}
}
}
/* 출력 결과
0
0
0
0
0
...[생략]...
*/
보다시피 threadFunc는 지속적으로 Size64 구조체를 new 시키고 있는데요, 따라서 16바이트가 넘어가는 구조체가 정말 힙에 할당된다면 Main에서 GC.CollectionCount를 구하는 코드에서 n 값은 계속 증가해야 합니다. 물론, 실행해 보면 n 값은 언제까지고 0으로만 나옵니다.
반대로 Size64를 구조체가 아닌 class로 정의하면,
public class Size64
{
public long l1;
public long l2;
public long l3;
public long l4;
public long l5;
public long l6;
public long l7;
public long l8;
}
/* 출력 결과
0
1984
4420
6959
9454
11650
14186
...[생략]...
*/
이제는 GC.CollectionCount가 반환하는 n 값이 빠르게 증가하는 것을 확인할 수 있습니다.
혹시나 그럼, 어느 크기에선가는 heap으로 할당되지 않을까요? 이에 대한 답이 예전에 설명한 예제에 있습니다.
CER(Constrained Execution Region)이란?
; https://www.sysnet.pe.kr/2/0/11868#large_sized_struct
fixed 예약어를 사용하면 struct의 크기를 1MB 크기까지 간단하게 늘릴 수 있는데요,
// 스택 크기 기본값 - 32비트 1MB, 64비트 4MB
// 따라서 32비트로 빌드한 경우
unsafe struct Big
{
public fixed byte Bytes[1_048_576]; // 일반적인 스택 메모리의 크기가 1MB이므로 StackOverflowException 발생
}
따라서, 위의 구조체를 생성하면 (stack에 할당을 시도하므로) StackOverflowException 예외가 발생합니다.
// 32비트로 빌드한 경우
Big big = new Big(); // StackOverflowException 발생
// 또는,
Big big; // 구조체의 특성상 new를 하지 않아도 할당하므로 StackOverflowException 발생
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]