Pelo que entendi, em Java, a memória da pilha contém primitivas e invocações de métodos e a memória heap é usada para armazenar objetos.
Suponha que eu tenha uma aula
class A {
int a ;
String b;
//getters and setters
}
Onde o primitivo
a
da classeA
será armazenado?Por que a memória heap existe? Por que não podemos armazenar tudo na pilha?
Quando o objeto é coletado como lixo, a pilha associada ao objeto é destruída?
Respostas:
A diferença básica entre pilha e pilha é o ciclo de vida dos valores.
Os valores da pilha existem apenas dentro do escopo da função em que são criados. Quando ele retorna, eles são descartados.
No entanto, os valores de heap existem no heap. Eles são criados em algum momento e destruídos em outro (pelo GC ou manualmente, dependendo do idioma / tempo de execução).
Agora, o Java armazena apenas primitivas na pilha. Isso mantém a pilha pequena e ajuda a manter os quadros individuais da pilha pequenos, permitindo assim mais chamadas aninhadas.
Os objetos são criados no heap e apenas as referências (que por sua vez são primitivas) são passadas na pilha.
Portanto, se você criar um objeto, ele será colocado no heap, com todas as variáveis que pertencem a ele, para que possa persistir após o retorno da chamada da função.
fonte
char
s são números e podem ser usados de forma intercambiável. As referências também são apenas números referentes a um endereço de memória, com 32 ou 64 bits de comprimento (embora não possam ser usados como tal - a menos que você esteja brincandosun.misc.Unsafe
).boolean
,byte
,short
,char
,int
,long
,float
Edouble
.)Onde os campos primitivos são armazenados?
Os campos primitivos são armazenados como parte do objeto que é instanciado em algum lugar . A maneira mais fácil de pensar onde é isso - é a pilha. No entanto , esse nem sempre é o caso. Conforme descrito na teoria e na prática de Java: Lendas do desempenho urbano, revisitadas :
Assim, além de dizer "o objeto é criado e o campo também existe", não se pode dizer se algo está na pilha ou na pilha. Observe que, para objetos pequenos e de curta duração, é possível que o 'objeto' não exista na memória como tal e, em vez disso, tenha seus campos colocados diretamente nos registradores.
O artigo conclui com:
Portanto, se você tiver um código parecido com:
onde o
...
não permitequx
deixar esse escopo,qux
pode ser alocado na pilha. Na verdade, isso é uma vitória para a VM, porque significa que ela nunca precisa ser coletada como lixo - ela desaparecerá quando sair do escopo.Mais sobre a análise de escape na Wikipedia. Para aqueles que desejam se aprofundar em documentos, Escape Analysis for Java da IBM. Para quem vem de um mundo C #, pode encontrar boas leituras de A pilha é um detalhe de implementação e A verdade sobre os tipos de valor, por Eric Lippert (são úteis para os tipos Java, pois muitos dos conceitos e aspectos são iguais ou semelhantes) . Por que os livros .Net falam sobre alocação de memória pilha versus pilha? também entra nisso.
Nos porquês da pilha e da pilha
Na pilha
Então, por que ter a pilha ou a pilha? Para coisas que deixam o escopo, a pilha pode ser cara. Considere o código:
Os parâmetros também fazem parte da pilha. Na situação em que você não tem um heap, você passaria o conjunto completo de valores na pilha. Isso é bom para
"foo"
pequenas strings ... mas o que aconteceria se alguém colocasse um arquivo XML enorme nessa string. Cada chamada copiava toda a cadeia enorme para a pilha - e isso seria um grande desperdício.Em vez disso, é melhor colocar os objetos que têm alguma vida fora do escopo imediato (passados para outro escopo, presos em uma estrutura que outra pessoa está mantendo, etc ...) em outra área chamada heap.
Na pilha
Você não precisa da pilha. Poderia-se, hipoteticamente, escrever uma linguagem que não use uma pilha (de profundidade arbitrária). Um antigo BASIC que aprendi na juventude o fez, só era possível fazer 8 níveis de
gosub
chamadas e todas as variáveis eram globais - não havia pilha.A vantagem da pilha é que, quando você tem uma variável que existe com um escopo, quando você sai desse escopo, o quadro da pilha é exibido. Simplifica realmente o que está lá e o que não está lá. O programa passa para outro procedimento, um novo quadro de pilha; o programa retorna ao procedimento e você retornou ao que vê seu escopo atual; o programa deixa o procedimento e todos os itens da pilha são desalocados.
Isso realmente facilita a vida da pessoa que está escrevendo o tempo de execução do código para usar uma pilha e uma pilha. Eles simplesmente muitos conceitos e maneiras de trabalhar no código, permitindo que a pessoa que escreve o código na linguagem seja liberada de pensar neles explicitamente.
A natureza da pilha também significa que ela não pode se fragmentar. A fragmentação da memória é um problema real com a pilha. Você aloca alguns objetos, coleta o lixo do meio e tenta encontrar espaço para o próximo grande a ser alocado. É uma bagunça. Ser capaz de colocar as coisas na pilha significa que você não precisa lidar com isso.
Quando algo é coletado de lixo
Quando algo é coletado, o lixo se foi. Mas é apenas lixo coletado porque já foi esquecido - não há mais referências ao objeto no programa que podem ser acessadas a partir do estado atual do programa.
Vou apontar que essa é uma simplificação muito grande da coleta de lixo. Existem muitos coletores de lixo (mesmo no Java - você pode ajustá-lo usando vários sinalizadores ( docs ).) Eles se comportam de maneira diferente e as nuances de como cada um faz as coisas são um pouco profundas para esta resposta. Noções básicas sobre coleta de lixo de Java para ter uma idéia melhor de como isso funciona.
Dito isto, se algo estiver alocado na pilha, ele não será coletado como parte
System.gc()
dele - será desalocado quando o quadro da pilha aparecer. Se algo estiver na pilha e referenciado a partir de algo na pilha, não será coletado lixo naquele momento.Por que isso importa?
Para a maior parte, a sua tradição. Os livros de texto escritos e as classes de compilador e a documentação de vários bits são importantes para o heap e a pilha.
No entanto, as máquinas virtuais de hoje (JVM e similares) fizeram um grande esforço para tentar manter isso escondido do programador. A menos que você esteja ficando sem um e outro e precise saber o motivo (em vez de apenas aumentar o espaço de armazenamento adequadamente), isso não importa muito.
O objeto está em algum lugar e está no local em que pode ser acessado corretamente e rapidamente pela quantidade adequada de tempo em que ele existe. Se estiver na pilha ou na pilha - isso realmente não importa.
fonte
fonte
No heap, a menos que o Java aloque a instância da classe na pilha como uma otimização após provar por meio da análise de escape que isso não afetará a semântica. Porém, este é um detalhe de implementação; portanto, para todos os propósitos práticos, exceto a micro-otimização, a resposta está "na pilha".
A memória da pilha deve ser alocada e desalocada na última ordem de saída. A memória heap pode ser alocada e desalocada em qualquer ordem.
Quando o objeto é coletado de lixo, não há mais referências apontando para ele da pilha. Se houvesse, eles manteriam o objeto vivo. As primitivas de pilha não são coletadas como lixo porque são destruídas automaticamente quando a função retorna.
fonte
A memória da pilha é usada para armazenar variáveis locais e chamadas de função.
Enquanto a memória heap é usada para armazenar objetos em Java. Não importa, onde o objeto é criado no código.
Nesse caso, a primitiva a está associada ao objeto de classe A. Por isso, cria na memória de pilha.
O Garbage Collector trabalha sob o escopo da memória Heap, destruindo objetos que não possuem cadeia de referência da raiz.
fonte
Para uma melhor compreensão (memória Heap / Stack):
fonte