Quando eu crio um objeto, a memória nova é alocada para os campos e métodos da instância ou apenas para os campos da instância

14

Eu tenho uma turma seguinte

class Student{

int rollNumber;
int marks;

public void setResult(int rollNumber, int marks){

    this.rollNumber=rollNumber;
    this.marks=marks;   
}

public void displayResult(){

    System.out.println("Roll Number= "+this.rollNumber+"   Marks= "+this.marks);

}
}

Agora eu crio dois objetos do tipo Student da seguinte maneira

Student s1=new Student();
Student s2=new Student();

Agora, dois conjuntos diferentes de memória são alocados para os campos da instância. Agora, minha pergunta é se a memória é alocada para os métodos ( setResulte displayResult) duas ou uma vez?

Consulte a figura a seguir e você pode me ajudar a dizer qual figura fornece as informações corretas.

insira a descrição da imagem aqui

Harish_N
fonte
1
Compartilhar sua pesquisa ajuda a todos . Conte-nos o que você tentou e por que ele não atendeu às suas necessidades. Isso demonstra que você dedicou um tempo para tentar ajudar a si mesmo, evita reiterar respostas óbvias e, acima de tudo, ajuda a obter uma resposta mais específica e relevante. Veja também How to Ask
gnat
3
Estou aprendendo java ... e em todos os materiais, eles dizem que sempre que criamos um objeto, uma nova memória é alocada em todos os campos da instância ... mas nenhum dos materiais disse se a nova memória será alocada para métodos ou não
Harish_N

Respostas:

13

O código para métodos faz parte do Class(de forma mais concisa,Class<Student> ) e é carregado na memória quando a classe é carregada pela primeira vez.

Dito isto, quando você executa qualquer método, é usada memória adicional para alocar memória a parâmetros, variáveis ​​locais, resultados de expressões temporárias, valores de retorno e assim por diante. Mas essa memória é alocada na pilha (a memória usada ao criar uma nova instância é alocada na pilha .

Conforme sua pergunta, deve ficar claro agora que a figura B está correta (embora não reflita o que acontece quando você realmente chama o método).

SJuan76
fonte
Está bem. Estou 90% claro agora ... Mas uma pequena dúvida .. Suponha que se eu criar 10 objetos do tipo Student, apenas 1 conjunto de memória nova será alocado para os métodos presentes na classe Student, enquanto 10 conjuntos de memória nova serão alocado para armazenar variáveis ​​de instância para 10 objetos .. Estou certo?
Harish_N
Certo. Pense que não são apenas as propriedades que consomem memória, há uma pequena sobrecarga relacionada à própria instância (uma instância de uma classe sem propriedades utilizará mais de 0 bytes de memória).
SJuan76
Só mais uma coisa ... Eu perguntei questão mantendo java em mente .... Será que a mesma coisa acontece em java .....
Harish_N
A Java Language Specification não diz nada sobre quanta memória é alocada quando e com que finalidade. Isso é deixado para o implementador, e cada implementador pode escolher de maneira diferente.
Jörg W Mittag
6

Os campos de instância (incluindo campos de propriedade) recebem N-cópias para N-objetos.

Os campos estáticos recebem uma única cópia por classe.

Métodos são blocos de bytecode (ou após JIT, blocos de instruções nativas) que fazem parte da "imagem" do programa ou do segmento de código executável. Os métodos já fazem parte da imagem do programa, pois fica no disco. Depois que a imagem é carregada pelo sistema operacional (ou CLR), há uma única cópia compartilhada do código do método.

Eles não fazem parte da "pilha" ou da alocação de tempo de execução em geral, exceto nos casos em que você pode usar o compilador hostável para compilar novos métodos em tempo real. Os métodos não são "alocados" como objetos e não são "alocados" em relação à criação do objeto. Eles meramente existem como parte do programa antes que um único objeto seja instanciado. Mesmo lambdas / delegados não são alocados em tempo real. O compilador cria classes sob demanda para implementar esses outros objetos de código aparentemente dinâmicos e eles também existem como parte da imagem do bytecode no disco.

ATUALIZAÇÕES por comentários:

O padrão da JVM tem o seguinte a dizer:

2.5.4 Área do método

A Java Virtual Machine possui uma área de método compartilhada entre todos os encadeamentos da Java Virtual Machine. A área do método é análoga à área de armazenamento para código compilado de uma linguagem convencional ou análoga ao segmento "texto" em um processo do sistema operacional. Ele armazena estruturas por classe, como o pool constante em tempo de execução, dados de campo e método, e o código para métodos e construtores, incluindo os métodos especiais (§2.9) usados ​​na inicialização de classes e instâncias e na interface.

A área do método é criada na inicialização da máquina virtual. Embora a área do método faça parte logicamente do heap, implementações simples podem optar por não coletar ou compactar o lixo. Esta versão da especificação Java Virtual Machine não determina o local da área de método ou as políticas usadas para gerenciar o código compilado. A área do método pode ter um tamanho fixo ou pode ser expandida conforme exigido pelo cálculo e pode ser contratada se uma área maior do método se tornar desnecessária. A memória da área do método não precisa ser contígua.

Portanto, é claro que (1) sim, a especificação não determina como isso é feito, mas (2) é análogo à área de armazenamento para código compilado de uma linguagem convencional, ou seja. o segmento de texto. Este é o ponto que estou afirmando.

codenheim
fonte
O que você está dizendo faz sentido, mas isso é realmente garantido pelo JLS? Normalmente, o JLS oferece aos implementadores muita margem de manobra em questões como essa.
Jörg W Mittag
Não tenho certeza sobre esse ponto, @ JörgWMittag. Tu podes estar certo. O ponto que tentei destacar é "new T ()" não aloca uma nova instância de um método. Quanto às especificidades da JVM, os carregadores de classes realmente armazenam o bytecode no heap, e acho que existem cenários possíveis em que as próprias classes são instanciadas e até coletadas de lixo. Mas são os detalhes de implementação do tempo de execução e, conceitualmente, a pilha de que estou falando é a pilha de "usuário". A classe e os métodos não são considerados dados no contexto normal do usuário. Mas como também podemos controlar um carregador de classes da área de usuário, acho que não sei.
Codenheim
O JLS nem fala sobre um monte, não é? É perfeitamente legal implementar Java com uma pilha dinâmica e sem heap, em vez de uma pilha de tamanho fixo finita e um heap dinâmico. O JLS também não diz nada sobre a JVM, é perfeitamente válido implementar o Java sem uma JVM.
Jörg W Mittag
Você está fazendo referência à JLS, mas estou falando da JVM. O padrão da JVM certamente discute heap. Você deve fornecer um escopo / tempo de vida variável que escapa ao escopo local da pilha. Quanto ao que é teoricamente possível, prefiro pensar em termos de "implementações conhecidas". Tenho certeza de que implementar uma JVM completa sem uma primitiva de heap é uma tarefa difícil ou mesmo impossível, pois a JVM não é uma máquina de pilha pura. Minha compreensão das máquinas Forth e outras arquiteturas de pilha pura é que pode ser possível se existe uma primitiva para acesso aleatório a variáveis, mas eu simplesmente não a vi.
Codenheim
@ JörgWMittag - eu adicionei à resposta algo que pode ser interessante para a nossa discussão. O ponto é que eu estava traçando uma analogia com o código ou segmento de texto tradicional nos sistemas de tempo de execução convencionais.
Codenheim
-4

objeto alocado na memória heap. quando o objeto é alocado, o slot para toda a variável de instância é criada e destruída quando o objeto é destruído. a variável de instância também é alocada na memória heap. E a variável local é criada na pilha no momento em que o método é chamado.

Abhishek Tripathi
fonte
1
Parece apenas repetir as informações fornecidas nas respostas anteriores.