이 메모리는 언제 사라지나

안녕하세요. 궁금한점이 있어 질문드립니다.

public void Func(bool param) {
  int a = 0;
  if(param) {
     int b = 0;  
  }
}

위에서 보이는 코드 중 b가 메모리에서 사라지는 타이밍이 언제일까요?

저는 if문 안에서 생성되었고 bif문 밖에서 참조될 수 없기 때문에

if문이 끝나는 타이밍이 없어진다고 이해가 되는데… 지나고 생각하니

이 이해가 잘못된 걸 수도 있다고 생각이 들어서 질문드립니다.

어차피 함수는 스택에 한번에 메모리가 올라가는거 같기도하고… 암튼 잘 모르겠습니다… ㅠ

혹시 언제 b가 메모리에서 사라지는지 알 수 있을까요?

감사합니다.

4개의 좋아요

스택 메모리는 스레드 생성시 할당되어 스레드가 종료되기 전까지 해제되지 않습니다. 그러므로 메모리에서 사라지는 시점은 관점에 따라 다르게 말할 수 있을 것 같습니다.

일단 위의 코드에서는 b의 메모리 위치의 값은 (코드에서 if 문 블럭 밖에서 접근이 안되는 것과 상관없이) 함수가 종료되는 시점까지 0입니다.

6개의 좋아요

카테고리를 모두의 Q&A로 변경 드립니다.

5개의 좋아요

If문 안과 밖이 상관이 없는거 같군요!!

알려주셔서 감사합니다!!

4개의 좋아요

@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 도 모두 해제 됩니다.

9개의 좋아요

위의 설명은 올바르지 않습니다. 운영체제가 스택을 교체하는 작업은 "SP 레지스터"의 값을 교체하는 것에 지나지 않습니다. 스택 데이터 자체를 복사하는 식의 작업이 아닙니다. 따라서 golang의 go routine이 그 이유로 인해 가벼운 것은 아닙니다.

그리고 닷넷의 경우도 스레드 스택의 초기 크기를 지정할 수 있습니다. 이에 대해서는 다음의 글을 참조하시고,

69. 스레드가 차지하는 기본 메모리? (sysnet.pe.kr)

또한, (32비트의 경우) 1MB의 스택을 예약하지만, 예약한 그 메모리가 처음부터 사용 가능하도록 commit된 것은 아닙니다. 관련해서는 다음의 글을 참고하세요.

작업 관리자에서의 "Commit size"가 가리키는 메모리의 의미 (sysnet.pe.kr)

10개의 좋아요

와…정정 감사드립니다!
잘못 알고 있었던 걸 수정하는 기쁨이란…!!

사실 위에 적지는 않았지만, .NET도 스레드 스택 사이즈를 변경할 수 있다고 언젠가 본 것은 같았습니다.
그 글에서 봤던게 ASP.NET Core의 경우엔 스레드 스택 사이즈가 기본값이 256KB 였나…그렇게 봤었던 거 같은데 확실하지 않아서 적지 않았었습니다.

5개의 좋아요

컨텍스트 스위칭에 대한 얘기가 나와서 도움이 될만한 영상 공유 드려요.
기억이 새록새록 하시리라 생각됩니다~

요약

컨텍스트 스위칭은 Process와 Thread 수준으로 나뉩니다.
컨텍스트 스위칭은 공통적으로 커널모드의 인터럽트에 의해 발생되며, 현재 스레드 또는 프로세스의 @kevin13 님이 말씀하신 SP를 포함한 각종 레지스터를 저장합니다. (다음에 다시 실행해야 되기 때문)
그리고 스위칭 대상 프로세스 또는 스레드의 상태를 레지스터에 복원합니다.
프로세스 스위칭은 프로세스간 메모리 주소 체계가 다르므로 메모리와 관련된 추가작업이 발생됩니다. (대표적으로 MMU, TLB)

MMU와 TLB 동작

엇! @마수리 님의 좋은 영상도 함께 공유 드립니다.

5개의 좋아요

막연하게 그냥 프로세스 간 컨텍스트 스위칭은 더 느리다고 알아왔는데 자세하게 알게 되었습니다!
감사합니다

3개의 좋아요