programing tip

C #의 스택 크기가 정확히 1MB 인 이유는 무엇입니까?

itbloger 2020. 9. 16. 07:25
반응형

C #의 스택 크기가 정확히 1MB 인 이유는 무엇입니까?


오늘날의 PC에는 많은 양의 물리적 RAM이 있지만 여전히 C #의 스택 크기는 32 비트 프로세스의 경우 1MB, 64 비트 프로세스의 경우 4MB입니다 ( C #의 스택 용량 ).

CLR의 스택 크기가 여전히 제한적인 이유는 무엇입니까?

2MB 또는 512KB가 아닌 정확히 1MB (4MB) 인 이유는 무엇입니까? 이 금액을 사용하기로 결정한 이유는 무엇입니까?

나는 그 결정이면의 고려 사항과 이유에 관심이 있습니다.


여기에 이미지 설명 입력

당신은 그 선택을 한 사람을보고 있습니다. David Cutler와 그의 팀은 기본 스택 크기로 1MB를 선택했습니다. .NET 또는 C #과는 관련이 없습니다. 이것은 그들이 Windows NT를 만들 때 정해졌습니다. 1 메가 바이트는 프로그램의 EXE 헤더 또는 CreateThread () winapi 호출이 스택 크기를 명시 적으로 지정하지 않을 때 선택하는 것입니다. 이것이 일반적인 방법이며 거의 모든 프로그래머가 OS를두고 크기를 선택합니다.

그 선택은 아마도 Windows NT 디자인보다 이전 일 것입니다. 역사는 이것에 대해 너무 모호합니다. Cutler가 그것에 관한 책을 쓰면 좋을 것입니다. 그러나 그는 작가가 된 적이 없습니다. 그는 컴퓨터 작동 방식에 엄청난 영향을 미쳤습니다. 그의 첫 번째 OS 디자인은 DEC 컴퓨터 용 16 비트 운영 체제 인 RSX-11M (Digital Equipment Corporation)이었습니다. 이는 8 비트 마이크로 프로세서를위한 최초의 괜찮은 OS 인 Gary Kildall의 CP / M에 큰 영향을 미쳤습니다. MS-DOS에 큰 영향을 미쳤습니다.

그의 다음 디자인은 가상 메모리를 지원하는 32 비트 프로세서 용 운영 체제 인 VMS였습니다. 매우 성공적입니다. 그의 다음 것은 회사가 해체되기 시작할 무렵 DEC에 의해 취소되어 값싼 PC 하드웨어와 경쟁 할 수 없었습니다. Cue Microsoft, 그들은 그에게 거절 할 수없는 제안을했습니다. 그의 동료들도 많이 합류했습니다. 그들은 Windows NT로 더 잘 알려진 VMS v2에서 작업했습니다. DEC는 그것에 대해 화를 냈고 돈은 그것을 해결하기 위해 손을 바 꾸었습니다. VMS가 이미 1 메가 바이트를 선택했는지 여부는 알 수 없지만 RSX-11 만 잘 알고 있습니다. 그럴 것 같지 않습니다.

충분한 역사. 1 메가 바이트는 많고 실제 스레드는 몇 킬로바이트 이상을 거의 사용하지 않습니다. 따라서 메가 바이트는 실제로 다소 낭비입니다. 그러나 수요 페이징 가상 메모리 운영 체제에서 감당할 수있는 낭비는 메가 바이트 일뿐 가상 메모리 입니다. 프로세서에는 4096 바이트마다 하나씩 숫자 만 표시됩니다. 실제로 주소를 지정할 때까지 실제 메모리, 컴퓨터의 RAM을 실제로 사용하지 않습니다.

원래 기본 프로그램을 수용하기 위해 1MB 크기가 선택 되었기 때문에 .NET 프로그램에서는 과도합니다. 큰 스택 프레임을 생성하고 스택에 문자열과 버퍼 (배열)를 저장하는 경향이 있습니다. 멀웨어 공격 벡터로 악명 높은 버퍼 오버플로는 데이터로 프로그램을 조작 할 수 있습니다. .NET 프로그램이 작동하는 방식이 아니라 문자열과 배열이 GC 힙에 할당되고 인덱싱이 확인됩니다. C #을 사용하여 스택에 공간을 할당하는 유일한 방법은 안전하지 않은 stackalloc 키워드를 사용하는 것입니다.

.NET에서 스택의 중요한 용도는 지터뿐입니다. 스레드 스택을 사용하여 MSIL을 기계 코드로 적시에 컴파일합니다. 필요한 공간의 양을 확인하거나 확인한 적이 없습니다. 코드의 특성과 최적화 프로그램의 활성화 여부에 따라 다르지만 수십 킬로바이트는 대략적인 추측입니다. 그렇지 않으면이 웹 사이트가 이름을 얻은 방법입니다. .NET 프로그램의 스택 오버플로는 매우 치명적입니다. 예외를 포착하려는 코드를 안정적으로 JIT하기에 충분한 공간 (3KB 미만)이 남아 있지 않습니다. Kaboom to desktop이 유일한 옵션입니다.

마지막으로, .NET 프로그램은 스택에서 매우 비생산적인 작업을 수행합니다. CLR은 스레드 스택을 커밋 합니다. 이는 스택의 크기를 예약하는 것이 아니라 필요할 때 스택을 항상 교체 할 수 있도록 운영 체제의 페이징 파일에 공간이 예약되어 있음을 의미하는 값 비싼 단어입니다. 커밋에 실패하면 치명적인 오류가 발생하며 프로그램이 무조건 종료됩니다. 이는 완전히 너무 많은 프로세스를 실행하는 RAM이 매우 적은 기계에서만 발생하며, 그러한 기계는 프로그램이 죽기 전에 당밀로 변했을 것입니다. 15 년 이상 전, 오늘이 아닌 가능한 문제. F1 경주 용 자동차처럼 작동하도록 프로그램을 조정하는 프로그래머는 <disableCommitThreadStack>.config 파일 요소를 사용 합니다.

Fwiw, Cutler는 운영 체제 설계를 중단하지 않았습니다. 그 사진은 그가 Azure에서 작업하는 동안 만들어졌습니다.


업데이트, .NET이 더 이상 스택을 커밋하지 않는다는 것을 알았습니다. 언제, 왜 이런 일이 발생했는지 정확히 모르겠지만 확인한 지 너무 오래되었습니다. 이 디자인 변경은 .NET 4.5 주변에서 발생했다고 생각합니다. 꽤 현명한 변화.


기본 예약 스택 크기는 링커에 의해 지정되며 개발자가 링크시 PE 값을 변경하거나 WinAPI 함수에 dwStackSize대한 매개 변수를 지정하여 개별 스레드에 대해 재정의 할 수 있습니다 CreateThread.

초기 스택 크기가 기본 스택 크기보다 크거나 같은 스레드를 생성하면 가장 가까운 1MB의 배수로 반올림됩니다.

Why the value equals to 1 MB for 32-bit processes and 4 MB for 64-bit? I think you should ask developers, who designed Windows, or wait until someone of them answers your question.

Probably Mark Russinovich knows that and you can contact him. Maybe you can find this information in his Windows Internals books earlier than sixth edition which describes less info about stacks rather than his article. Or maybe Raymond Chen knows reasons since he writes interesting things about Windows internals and its history. He can answer your question too, but you should post a suggestion to the Suggestion Box.

But at this time I'll try to explain some probable reasons why Microsoft have choose these values using MSDN, Mark's and Raymond's blogs.

The defaults have these values probably because in early times PCs were slow and allocating memory on the stack was much faster than allocating memory in the heap. And since stack allocations were much cheaper they were used, but it required a larger stack size.

So the value were the optimal reserved stack size for most of applications. It's optimal because allows to make a lot of nested calls and allocate memory on the stack to pass structures to calling functions. At the same time it allows to create a lot threads.

Nowadays these values are mostly used for backward compatibility, because structures which are passed as parameters to WinAPI functions are still allocated on the stack. But if you're not using stack allocations then a thread's stack usage will be significantly less than the default 1 MB and it is wasteful as Hans Passant mentioned. And to prevent this the OS commits only the first page of the stack (4 KB), if other isn't specified in the PE header of the application. Other pages are allocated on demand.

Some applications override reserved address space and initially committed to optimize memory usage. As an example, the maximum stack size of an IIS native process's thread is 256 KB (KB932909). And this decreasing of the default values is recommended by Microsoft:

가능한 한 작은 스택 크기를 선택하고 스레드 또는 파이버가 안정적으로 실행되는 데 필요한 스택을 커밋하는 것이 가장 좋습니다. 스택 용으로 예약 된 모든 페이지는 다른 용도로 사용할 수 없습니다.

출처 :

  1. 스레드 스택 크기 (Microsoft Docs)
  2. Windows의 한계 극복 : 프로세스 및 스레드 (Mark Russinovich)
  3. 기본적으로 기본 IIS 프로세스에서 생성되는 스레드의 최대 스택 크기는 256KB (KB932909)입니다.

참고 URL : https://stackoverflow.com/questions/28656872/why-is-stack-size-in-c-sharp-exactly-1-mb

반응형