Por que os livros sobre .Net falam sobre alocação de memória de pilha versus heap?

36

Parece que todos os livros .net falam sobre tipos de valor versus tipos de referência e faz questão de indicar (muitas vezes incorretamente) onde cada tipo é armazenado - o heap ou a pilha. Geralmente é nos primeiros capítulos e apresentado como um fato muito importante. Acho que ele é abordado em exames de certificação . Por que o empilhamento vs heap importa para (iniciante) desenvolvedores .Net? Você aloca coisas e simplesmente funciona, certo?

    
por Greg 03.11.2010 / 18:50
fonte

8 respostas

37

Estou me convencendo de que a principal razão pela qual essa informação é considerada importante é a tradição. Em ambientes não gerenciados, a distinção entre pilha e heap é importante e temos que alocar e excluir manualmente memória que usamos. Agora, a coleta de lixo cuida do gerenciamento, então eles ignoram esse bit. Eu não acho que a mensagem tenha realmente passado que nós não temos que nos preocupar com qual tipo de memória é usada.

Como Fede salientou, Eric Lippert tem algumas coisas muito interessantes a dizer sobre isso: link .

À luz dessas informações, você pode ajustar meu primeiro parágrafo para basicamente ler: "A razão pela qual as pessoas incluem essas informações e assumem que isso é importante é por causa de informações incorretas ou incompletas combinadas com a necessidade de conhecimento no passado." p>

Para aqueles que acham que ainda é importante por motivos de desempenho: Quais ações você tomaria para mover algo do heap para a pilha se você medisse as coisas e descobrisse que isso importava? Mais provavelmente, você encontraria uma maneira completamente diferente de melhorar o desempenho para a área do problema.

    
por 03.11.2010 / 19:09
fonte
36

It seems like every .NET book talks about value types vs reference types and makes it a point to (often incorrectly) state where each type is stored - the heap or the stack. Usually it's in the first few chapters and presented as some all-important fact.

Eu concordo completamente; Eu vejo isso o tempo todo.

Why do .NET books talk about stack vs heap memory allocation?

Uma parte do motivo é porque muitas pessoas vieram para C # (ou outras linguagens .NET) de um plano de fundo C ou C ++. Como essas linguagens não impõem a você as regras sobre o tempo de armazenamento, você precisa conhecer essas regras e implementar o programa cuidadosamente para segui-las.

Agora, conhecer essas regras e segui-las em C não exige que você entenda "o heap" e "a pilha". Mas se você entender como as estruturas de dados funcionam, é mais fácil entender e seguir as regras.

Ao escrever um livro para iniciantes, é natural que um autor explique os conceitos na mesma ordem em que eles os aprenderam. Isso não é necessariamente a ordem que faz sentido para o usuário. Recentemente, fui editor técnico do livro de iniciação C # 4 de Scott Dorman, e uma das coisas que mais gostei foi que Scott escolheu uma ordem bem sensata para os tópicos, em vez de começar sobre o que realmente são tópicos avançados em gerenciamento de memória. / p>

Outra parte do motivo é que algumas páginas na documentação da MSDN enfatizam strongmente as considerações de armazenamento. Documentação do MSDN particularmente antiga que ainda está por aí desde os primeiros dias. Grande parte dessa documentação tem erros sutis que nunca foram extirpados, e é preciso lembrar que ela foi escrita em um determinado momento da história e para um público específico.

Why does stack vs heap even matter to (beginner) .NET developers?

Na minha opinião, isso não acontece. O que é muito mais importante entender é coisas como:

  • Qual é a diferença na semântica de cópia entre um tipo de referência e um tipo de valor?
  • Como um parâmetro "ref int x" se comporta?
  • Por que os tipos de valor devem ser imutáveis?

E assim por diante.

You allocate stuff and it just works, right?

Esse é o ideal.

Agora, existem situações em que isso importa. A coleta de lixo é incrível e relativamente barata, mas não é gratuita. Copiar pequenas estruturas ao redor é relativamente barato, mas não é gratuito. Há cenários de desempenho realistas nos quais você precisa equilibrar o custo da pressão de coleta com o custo de cópias excessivas. Nesses casos, é muito útil ter um strong entendimento do tamanho, localização e tempo de vida real de toda a memória relevante.

Da mesma forma, há cenários de interoperabilidade realistas nos quais é necessário saber o que está na pilha e o que está no heap e o que o coletor de lixo poderia estar movimentando. É por isso que o C # possui recursos como "fixed", "stackalloc" e assim por diante.

Mas esses são todos cenários avançados. Idealmente, um programador iniciante não precisa se preocupar com nada disso.

    
por 09.11.2010 / 17:03
fonte
13

Vocês estão todos perdendo o ponto. A razão pela qual a distinção entre pilha / heap é importante é por causa do escopo .

struct S { ... }

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

Quando x sai do escopo, o objeto criado é categoricamente desaparecido . Isso é somente porque é alocado na pilha, não no heap. Não há nada que possa ter entrado na parte "..." do método que possa mudar esse fato. Em particular, quaisquer atribuições ou chamadas de método só poderiam ter feito cópias do S struct, não criado novas referências a ele para permitir que ele continuasse vivo.

class C { ... }

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

História totalmente diferente! Como x está agora no heap , seu objeto (ou seja, o objeto em si , não uma cópia dele) pode muito bem continuar a viver depois de x sai do escopo. Na verdade, a única maneira de não continuar a continuar é se x for a única referência a ele. Se as atribuições ou chamadas de método na parte "..." tiverem criado outras referências que ainda estão "ativas" no momento em que x sair do escopo, esse objeto continuará vivo.

Esse é um conceito muito importante, e a única maneira de realmente entender "o que e por que" é saber a diferença entre a alocação de pilha e heap.

    
por 16.11.2010 / 14:16
fonte
5

Quanto a WHY, eles cobrem o tópico, eu concordo com @Kirk que é um conceito importante, que você tem que entender. Quanto melhor você conhecer os mecanismos, melhor você poderá fazer ótimos aplicativos que funcionem sem problemas.

Agora Eric Lippert parece concordar com você que o tópico não é corretamente coberto pela maioria dos autores. Eu recomendo que você leia o blog dele para conseguir um grande entendimento do que está acontecendo.

    
por 03.11.2010 / 19:02
fonte
5

Bem, eu achei que esse é o objetivo dos ambientes gerenciados. Eu até chego a chamar isso de um detalhe de implementação do tempo de execução subjacente no qual você NÃO deveria fazer suposições, porque poderia mudar a qualquer momento.

Eu não sei muito sobre o .NET, mas, tanto quanto eu sei, o seu JITted antes da execução. O JIT, por exemplo, poderia realizar análise de escape e o que não e de repente você estaria tendo objetos deitado sobre a pilha ou apenas em alguns registros. Você não pode saber disso.

Suponho que alguns livros cobrem isso simplesmente porque os autores atribuem grande importância a isso, ou porque eles assumem que o público o faz (por exemplo, se você escreveu um "C # para programadores de C ++", provavelmente deveria abordar o assunto).

No entanto, acho que não há muito mais a dizer do que "memória é gerenciada". Caso contrário, as pessoas podem tirar conclusões erradas.

    
por 03.11.2010 / 19:02
fonte
2

Você precisa entender como a alocação de memória funciona para usá-la com eficiência, mesmo que não seja necessário gerenciá-la explicitamente. Isso se aplica a praticamente todas as abstrações da ciência da computação.

    
por 03.11.2010 / 18:53
fonte
2

Pode haver alguns casos extremos em que isso pode fazer a diferença. O espaço de pilha padrão é de 1 meg enquanto o heap é de vários gig. Portanto, se sua solução contiver um grande número de objetos, você poderá ficar sem espaço na pilha e ter muito espaço de pilha.

No entanto, na maior parte, é bastante acadêmico.

    
por 03.11.2010 / 22:08
fonte
0

Como você disse, o C # deve abstrair o gerenciamento de memória e a alocação de pilha versus pilha são detalhes de implementação que, em teoria, o desenvolvedor não precisa saber.

O problema é que algumas coisas são realmente difíceis de explicar de maneira intuitiva sem se referir a esses detalhes de implementação. Tente explicar o comportamento observável quando você modifica os tipos de valores mutáveis - é quase impossível fazer sem referir-se à distinção pilha / pilha. Ou tente explicar por que até mesmo ter tipos de valor na linguagem, em primeiro lugar, e quando você os usaria? Você precisa entender a distinção para entender a linguagem.

Observe que livros sobre o Python ou o JavaScript não fazem grande diferença se eles mencionarem isso. Isso ocorre porque tudo é heap alocado ou imutável, o que significa que a semântica de cópia diferente nunca entra em jogo. Nessas linguagens a abstração da memória funciona, em C # ela está com vazamento.

    
por 30.08.2016 / 08:23
fonte

Tags