@dimohy 님께서 말씀하신대로 .NET에서 스택은 Thread 의 자원입니다.
따라서 Thread가 해제되기 전까지는 Stack 자체는 제거되지 않습니다.
검색하면 나오는 부분이지만, .NET은 32비트에서 스레드 1개당 1MB의 스택을 예약하고, 64비트에서는 스레드 1개당 4MB의 스택을 예약합니다. (C++의 경우 VS에서 Stack 사이즈 변경가능, go lang의 go routine의 경우 2KB)
우리가 컨텍스트 스위칭이라고 불리는 작업에는 이 스레드 스택을 교체하는 작업도 있습니다. 그래서 go routine같은게 stack 사이즈가 작다보니 가볍다고 하는 것이죠.
우리가 아무것도 안하는 단순한 무한루프 헬로우 월드 앱에서 메모리가 막 올라가는 이유 중 하나가 .NET 프로세스는 프로세스 1개 당 1개의 ThreadPool이 있고, 이 ThreadPool에 기본값 5개의 Thread가 예약되어 있고 32비트라면 각각 1MB씩 총 5MB를 차지하고 있습니다. (64비트라면 각각 4MB씩 20MB)
일반적으로 우리가 스택,힙,코드,데이터에 저장된다고 표현하는 것 중 스택의 풀네임은 사실 스레드 스택인 것입니다.
스택오버플로우가 나는 것도 현재 작업 중인 스레드의 스택에 1MB 혹은 4MB에 데이터가 넘쳤기 때문입니다.
그리고 이 쌓아지는 데이터는 보통의 경우 메서드를 많이 호출해서 다량의 stack frame이 중첩이 되다가 터지는 것일 겁니다.
팩토리얼 같은 재귀 함수가 계속 돌아가면 이 stack frame을 무수히 쌓다가 1MB or 4MB가 넘어가면 터지는 것입니다.
따라서 메서드를 만들때 그 함수의 파라미터, 함수 안의 지역변수, 리턴어드레스 등의 정보가 모여서 stack frame 이라는 메모리 덩어리를 생성하고 이것을 스레드 스택에 쌓고, code 영역에서 메서드를 실행한 뒤, 리턴어드레스를 통해 다시 스레드스택으로 돌아와서 내가 실행한 stack frame을 해제한 다음 다시 다음 stack frame을 쌓을 수 있게 되는 것입니다.
따라서 예제코드에서 Func 메서드를 실행 시, bool param, int a, int b를 포함한 stack frame을 생성한 뒤 Func 함수가 종료되면 stack frame이 해제 되기 때문에 param, a, b 도 모두 해제 됩니다.
컨텍스트 스위칭에 대한 얘기가 나와서 도움이 될만한 영상 공유 드려요.
기억이 새록새록 하시리라 생각됩니다~
요약
컨텍스트 스위칭은 Process와 Thread 수준으로 나뉩니다.
컨텍스트 스위칭은 공통적으로 커널모드의 인터럽트에 의해 발생되며, 현재 스레드 또는 프로세스의 @kevin13 님이 말씀하신 SP를 포함한 각종 레지스터를 저장합니다. (다음에 다시 실행해야 되기 때문)
그리고 스위칭 대상 프로세스 또는 스레드의 상태를 레지스터에 복원합니다.
프로세스 스위칭은 프로세스간 메모리 주소 체계가 다르므로 메모리와 관련된 추가작업이 발생됩니다. (대표적으로 MMU, TLB)