.Net 서적이 스택 대 힙 메모리 할당에 대해 이야기하는 이유는 무엇입니까?


36

모든 .net 책은 값 유형과 참조 유형에 대해 이야기하고 각 유형이 저장되는 위치 (힙 또는 스택)를 가리키게합니다 (종종 부정확 한). 일반적으로 처음 몇 장에 있으며 중요한 사실로 제시됩니다. 인증 시험 에도 적용되는 것 같습니다 . 스택 대 힙이 (초보자) .Net 개발자에게 중요한 이유는 무엇입니까? 당신은 물건을 할당하고 작동합니다, 그렇죠?


11
일부 저자는 초보자에게 무엇을 가르치는 것이 중요하며 관련없는 소음이 무엇인지에 대한 판단이 잘못되었습니다. 내가 최근에 본 책에서, 액세스 수정 자에 대한 첫 번째 언급은 이미 protected internal을 포함 하고 있는데, 이것은 6 년 동안 C #에서 사용한 적이 없습니다.
Timwi

1
내 생각 엔 그 부분에 대한 원본 .Net 문서를 작성한 사람이 그것을 많이 만들었고 그 문서는 저자가 원래 책을 기반으로 한 것이므로 그대로 유지되었다는 것입니다.
그렉

값 유형이 전체를 복사하고 참조가 아니라고 말하면 참조가 사용되는 이유를 이해하는 것이 더 이해하기 쉽고 값이 저장된 위치는 구현에 따라 다르고 심지어 관련성이 없을 수도 있습니다.
트리니다드

인터뷰화물 컬트?
Den

답변:


37

이 정보가 중요하게 여겨지는 주된 이유는 전통 이라고 확신합니다 . 관리되지 않는 환경에서는 스택과 힙 간의 구별이 중요하므로 사용하는 메모리를 수동으로 할당하고 삭제해야합니다. 이제 가비지 콜렉션이 관리를 처리하므로 해당 비트를 무시합니다. 나는 어떤 유형의 메모리가 사용되는지 신경 쓰지 않아도된다는 메시지를 실제로 얻지 못했다고 생각합니다.

Fede가 지적한 바와 같이, 에릭 Lippert의이에 대해 할 말이 아주 흥미로운 일이 있습니다 http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx .

그 정보에 비추어 볼 때, 첫 번째 단락을 기본적으로 읽도록 조정할 수 있습니다. "사람들이이 정보를 포함하고 중요하다고 생각하는 이유는 과거에이 지식이 필요했던 부정확하거나 불완전한 정보 때문입니다."

성능상의 이유로 여전히 중요하다고 생각하는 사람들을 위해 : 무언가를 측정하고 그것이 중요하다는 것을 알면 어떤 것을 힙에서 스택으로 옮기기 위해 어떤 조치를 취 하시겠습니까? 아마도 문제 영역의 성능을 개선하는 완전히 다른 방법을 찾을 것입니다.


6
일부 프레임 워크 구현 (특히 Xbox의 소형)에서는 렌더링 기간 (게임 자체) 동안 가비지 수집을 줄이기 위해 구조체를 사용하는 것이 좋습니다. 여전히 다른 곳에서는 일반 유형을 사용하지만 게임 중에 GC가 실행되지 않도록 사전 할당됩니다. 그것은 .NET에서 알고있는 스택 대 힙에 관한 유일한 최적화에 관한 것이며 컴팩트 프레임 워크 및 실시간 프로그램의 요구에 매우 적합합니다.
CodexArcanum

5
나는 대부분 전통의 주장에 동의합니다. 어느 시점에서 많은 숙련 된 프로그래머가 정확하고 효율적인 코드를 원할 경우이 문제가 중요한 저수준 언어로 프로그래밍되었을 수 있습니다. 그러나 관리되지 않는 언어 인 C ++를 예로 들어 보겠습니다. 공식 사양에서는 실제로 자동 변수 스택에 있어야 한다고 말하지 않습니다 . C ++ 표준은 스택과 힙을 구현 세부 정보로 취급합니다. +1
stakx

36

모든 .NET 서적은 값 유형과 참조 유형에 대해 이야기하고 각 유형이 저장되는 위치 (힙 또는 스택)를 가리키게합니다 (종종 잘못). 일반적으로 처음 몇 장에 있으며 중요한 사실로 제시됩니다.

나는 완전히 동의한다. 나는 이것을 항상 본다.

.NET 서적이 스택 대 힙 메모리 할당에 대해 이야기하는 이유는 무엇입니까?

그 이유 중 하나는 많은 사람들이 C 또는 C ++ 배경에서 C # (또는 다른 .NET 언어)을 사용했기 때문입니다. 이러한 언어는 스토리지 수명에 대한 규칙을 적용하지 않으므로 해당 규칙을 알고이를 따르기 위해 프로그램을 신중하게 구현해야합니다.

이제 이러한 규칙을 알고 C에서 규칙을 따를 때 "힙"과 "스택"을 이해 하지 않아도 됩니다. 그러나 데이터 구조의 작동 방식을 이해하면 규칙을 이해하고 따르는 것이 더 쉬운 경우가 많습니다.

초보자 용 책을 쓸 때 저자는 개념 배운 순서대로 설명하는 것이 당연 합니다. 반드시 사용자에게 맞는 순서는 아닙니다. 나는 최근 Scott Dorman의 C # 4 초급 책의 기술 편집자였으며, 내가 좋아했던 것 중 하나는 Scott이 메모리 관리에서 실제로 고급 주제를 시작하는 것이 아니라 주제에 대해 꽤 합리적인 순서를 선택했다는 것입니다.

그 이유 중 또 다른 부분은 MSDN 설명서의 일부 페이지가 스토리지 고려 사항을 강력하게 강조하기 때문입니다. 초기부터 아직도 남아있는 특히 오래된 MSDN 설명서. 그 문서의 대부분은 아직까지도 절제된 적이없는 미묘한 오류를 가지고 있으며, 특정 시점에 특정 청중을 위해 쓰여졌다는 것을 기억해야합니다.

스택 대 힙이 (초보자) .NET 개발자에게 중요한 이유는 무엇입니까?

제 생각에는 그렇지 않습니다. 훨씬 더 이해해야 할 것은 다음과 같습니다.

  • 참조 유형과 값 유형 사이의 복사 의미의 차이점은 무엇입니까?
  • "ref int x"매개 변수는 어떻게 작동합니까?
  • 값 유형을 변경할 수없는 이유는 무엇입니까?

등등.

당신은 물건을 할당하고 작동합니다, 그렇죠?

이상적입니다.

이제 중요한 상황이 있습니다. 가비지 콜렉션은 훌륭하고 상대적으로 저렴하지만 무료는 아닙니다. 작은 구조를 복사하는 것은 비교적 저렴하지만 무료는 아닙니다. 과도한 복사 비용과 수집 압력 비용의 균형을 유지해야하는 현실적인 성능 시나리오가 있습니다. 이 경우 모든 관련 메모리의 크기, 위치 및 실제 수명을 잘 이해하는 것이 매우 도움이됩니다.

마찬가지로, 스택에 무엇이 있고 힙에 무엇이 있는지, 가비지 콜렉터가 이동할 수있는 것을 알아야하는 현실적인 interop 시나리오가 있습니다. 이것이 C #에 "fixed", "stackalloc"등과 같은 기능이있는 이유입니다.

그러나 이것들은 모두 고급 시나리오입니다. 이상적으로 초보자 프로그래머는 이러한 것들에 대해 걱정할 필요가 없습니다.


2
답변 Eric에게 감사합니다. 주제에 대한 귀하의 최근 블로그 게시물은 실제로 질문을 게시하라는 메시지를 표시합니다.
그렉

13

너희들 모두 요점을 놓쳤다. 스택 / 힙 구분이 중요한 이유는 범위 때문입니다 .

struct S { ... }

void f() {
    var x = new S();
    ...
 }

일단 x가 범위를 벗어나, 생성 된 객체는 절대적으로되어 갔다 . 이는 힙이 아닌 스택에 할당되기 때문입니다. 그 사실을 바꿀 수있는 방법의 "..."부분에 들어갈 수있는 것은 없습니다. 특히, 할당이나 메소드 호출은 S 구조체의 복사본 만 만들 수 있었지만 계속 살아 남기 위해 새로운 참조를 만들지 않았습니다.

class C { ... }

void f() {
     var x = new C();
     ...
}

완전히 다른 이야기! x는 지금이기 때문에 , 그 객체 (즉, 객체 자체 가 아니라 그것의 사본) 아주 잘 이후에 계속 살 수 x가 범위를 벗어나. 실제로, x 가 유일한 참조 인 경우에만 계속 살아남지 못할 수 있습니다. "..."부분의 할당 또는 메소드 호출이 x 가 범위를 벗어날 때까지 "실제"인 다른 참조를 생성 한 경우 해당 객체는 계속 작동합니다.

그것은 매우 중요한 개념이며, "무엇을 왜"를 진정으로 이해하는 유일한 방법은 스택과 힙 할당의 차이점을 아는 것입니다.


나는 스택 / 힙 토론과 함께 책에서 이전에 제시 된 주장을 보지 못했지만 좋은 것입니다. +1
Greg

2
방식 때문에 C #의 클로저를 발생은 코드가 ...발생할 수 x표시된 범위 버틸 따라서 컴파일러 생성 클래스 필드로 변환하고,. 개인적으로, 나는 암묵적 호이 스팅에 대한 아이디어를 불쾌하게 생각하지만 언어 설계자들은 그것을 게양하려고합니다 (호이 스팅되는 변수가 선언에 무언가를 지정하도록 요구하는 것과 대조적으로). 프로그램의 정확성을 보장하기 위해 종종 개체에 존재할 수있는 모든 참조를 고려해야합니다. 루틴이 리턴 될 때까지 전달 된 참조의 사본이 남아 있지 않다는 것을 알면 유용합니다.
supercat

1
'구조가 스택에 있습니다'와 관련하여, 저장 위치가로 선언 structType foo되면 저장 위치 foo는 해당 필드의 내용을 보유합니다. foo스택에 있으면 해당 필드도 마찬가지입니다. foo힙에 있으면 해당 필드도 마찬가지입니다. 경우 foo네트워크 애플 II에, 그래서 그것의 필드입니다. 반대로 foo클래스 유형 인 경우 null, 또는 객체에 대한 참조 를 보유 합니다. 클래스 유형 foo이 객체의 필드를 보유한다고 말할 수있는 유일한 상황은 클래스 의 유일한 필드이고 자체에 대한 참조를 보유한 경우입니다.
supercat

+1, 나는 당신의 통찰력을 여기에서 좋아하고 그것이 타당하다고 생각합니다 ... 그러나, 왜 책이이 주제를 깊이있게 다루는 지에 대한 정당화는 아닙니다. 여기에서 설명한 내용이 해당 도서의 3 장 또는 4 장을 대체하고 더 도움이 될 것 같습니다.
Frank V

1
내가 아는 바에 따르면, 구조체는 항상 스택에 가지 않아도됩니다.
sara

5

그들이 주제를 다루는 이유에 관해서는 @Kirk이 중요한 개념이며 이해해야한다는 데 동의합니다. 메커니즘을 더 잘 알수록 원활하게 작동하는 훌륭한 응용 프로그램을 만들 수 있습니다.

이제 Eric Lippert 는 대부분의 저자가 주제를 제대로 다루지 않는다는 데 동의하는 것 같습니다. 나는 그의 블로그를 읽고 그 아래에 무엇이 있는지에 대한 큰 이해를 얻는 것이 좋습니다.


2
에릭의 글은 가치와 참조 유형의 명백한 특성이라는 점만으로도 구현이 동일하게 유지 될 것으로 기 대해서는 안된다는 점을 지적합니다. 스택없이 C #을 다시 구현하는 효율적인 방법이 있다고 제안하는 것은 상당히 의문의 여지가 있지만 그의 요지는 정확합니다. 언어 사양의 일부가 아닙니다. 따라서 내가 생각할 수있는이 설명을 사용하는 유일한 이유는 다른 언어, 특히 C를 아는 프로그래머들에게 그 우화가 유용하다는 것입니다. 그 우화를 아는 한, 많은 문헌은 명확하지 않습니다.
Jeremy

5

글쎄요, 그것이 관리되는 환경의 요점이라고 생각했습니다. 나는 심지어 언제든지 변경 될 수 있기 때문에 가정하지 말아야 할 기본 런타임의 구현 세부 사항을 이것을 호출하는 한까지 갔다.

.NET에 대해서는 잘 모르지만 실행하기 전에 JITted. 예를 들어, JIT는 이스케이프 분석을 수행 할 수 있으며 갑자기 스택에 또는 일부 레지스터에 객체가있는 것은 아닙니다. 당신은 이것을 알 수 없습니다.

필자는 저자가 그 책을 중요하게 여기거나 청중이 생각하기 때문에 일부 책에 단순히 해당 내용이 포함되어 있다고 가정합니다.

그럼에도 불구하고, 나는 "메모리 관리"라는 말보다 더 많은 것이 없다고 생각합니다. 그렇지 않으면 사람들은 잘못된 결론을 도출 할 수 있습니다.


2

명시 적으로 관리하지 않아도 메모리 할당이 효율적으로 사용되도록 메모리 할당이 어떻게 작동하는지 이해해야합니다. 이것은 컴퓨터 과학의 거의 모든 추상화에 적용됩니다.


2
관리되는 언어에서는 값 형식과 참조 형식의 차이점을 알아야하지만 그 외에는 차축이 어떻게 관리되는지에 대한 차축을 쉽게 감쌀 수 있습니다. 예를 보려면 여기를 참조하십시오 : stackoverflow.com/questions/4083981/…
Robert Harvey

나는 Robert에 동의해야합니다

힙 할당과 스택 할당의 차이점은 값과 참조 유형의 차이점을 정확하게 설명하는 것입니다.
제레미


1
힙과 스택 할당 의 차이점 값 유형과 참조 유형이 힙에 있지만 시간이 다르기 때문에 값 유형과 참조 유형 간의 다른 동작을 설명 할 수 없습니다 . 더 중요한 것은 참조 유형과 값 유형에 대해 참조 별 전달을 사용해야하는 경우입니다. 이것은 단지 "값 유형 또는 참조 유형"에 의존하며 "힙에 있지"는 않습니다.
Tim Goodman

2

차이를 만들 수있는 몇 가지 경우가있을 수 있습니다. 기본 스택 공간은 1meg이고 힙은 몇 기가입니다. 따라서 솔루션에 많은 수의 객체가 있으면 많은 힙 공간을 유지하면서 스택 공간이 부족할 수 있습니다.

그러나 대부분은 꽤 학문적입니다.


예. 그러나이 책 중 어느 것도 참조 자체가 스택에 저장되어 있음을 설명하는 데 어려움을 겪고 있습니다. 따라서 참조 유형이 많거나 값 유형이 많더라도 여전히 스택 오버플로가 발생할 수 있습니다.
Jeremy

0

당신이 말했듯이 C #은 메모리 관리를 추상화해야하며 힙 대 스택 할당은 이론적으로 개발자가 알 필요가없는 구현 세부 사항입니다.

문제는 이러한 구현 세부 사항을 참조하지 않고 직관적으로 설명하기 어려운 것이 있다는 것입니다. 변경 가능한 값 유형을 수정할 때 관찰 가능한 동작을 설명하십시오. 스택 / 힙 구별을 참조하지 않고는 거의 불가능합니다. 또는 왜 언어에 가치 유형이 있고 왜 언제 사용할 것인지 설명해보십시오. 언어를 이해하려면 차이를 이해해야합니다.

파이썬이나 자바 스크립트에 관한 책은 심지어 언급하더라도 큰 도움이되지 않습니다. 모든 것이 힙 할당되거나 불변이기 때문에 서로 다른 복사 의미론이 작동하지 않습니다. 이러한 언어에서는 메모리 추상화가 작동하고 C #에서는 누수가 발생합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.