AFAIK, a especificação da JVM (escrita em inglês) não menciona quando exatamente um objeto (ou um valor) deve ser excluído e deixa isso para a implementação (da mesma forma para o R5RS ). De alguma forma, requer ou sugere um coletor de lixo, mas deixa os detalhes para a implementação. E da mesma forma para a especificação Java.
Lembre-se de que linguagens de programação são especificações (de sintaxe , semântica , etc ...), não implementações de software. Uma linguagem como Java (ou sua JVM) possui muitas implementações. Sua especificação é publicada , pode ser baixada (para que você possa estudá-la) e escrita em inglês. §2.5.3 O monte de especificações da JVM menciona um coletor de lixo:
O armazenamento de heap para objetos é recuperado por um sistema de gerenciamento de armazenamento automático (conhecido como coletor de lixo); objetos nunca são desalocados explicitamente. A Java Virtual Machine não assume nenhum tipo específico de sistema de gerenciamento automático de armazenamento
(a ênfase é minha; a finalização BTW é mencionada no §12.6 da especificação Java e um modelo de memória está no §17.4 da especificação Java)
Portanto (em Java), você não deve se importar quando um objeto é excluído e pode codificar como se isso não acontecesse (raciocinando em uma abstração na qual você ignora isso). É claro que você precisa se preocupar com o consumo de memória e o conjunto de objetos vivos, o que é uma pergunta diferente . Em vários casos simples (pense em um programa "olá mundo"), você é capaz de provar - ou se convencer - que a memória alocada é bastante pequena (por exemplo, menos de um gigabyte) e então não se importa com nada exclusão de objetos individuais . Em mais casos, você pode se convencer de que os objetos vivos(ou alcançáveis, que é um superconjunto - mais fácil de raciocinar - sobre os vivos) nunca excede um limite razoável (e então você depende do GC, mas não se importa como e quando a coleta de lixo acontece). Leia sobre a complexidade do espaço .
Eu acho que em várias implementações da JVM executando um programa Java de curta duração como o hello world, o coletor de lixo não é acionado e nenhuma exclusão ocorre. AFAIU, esse comportamento está em conformidade com as inúmeras especificações Java.
A maioria das implementações da JVM usa técnicas de cópia geracional (pelo menos para a maioria dos objetos Java, aqueles que não usam finalização ou referências fracas ; e a finalização não é garantida que acontece em pouco tempo e pode ser adiada, portanto, é apenas um recurso útil que seu código não deve depende muito disso) em que a noção de excluir um objeto individual não faz sentido (uma vez que um grande bloco de memória - que contém zonas de memória para muitos objetos -, talvez vários megabytes ao mesmo tempo, é liberado ao mesmo tempo).
Se a especificação da JVM exigisse que cada objeto fosse excluído exatamente o mais rápido possível (ou simplesmente colocasse mais restrições na exclusão do objeto), técnicas de GC geracionais eficientes seriam proibidas e os projetistas de Java e da JVM teriam sido prudentes em evitar isso.
BTW, pode ser possível que uma JVM ingênua que nunca exclua objetos e não libere memória possa estar em conformidade com as especificações (a letra, não o espírito) e certamente possa executar uma coisa de olá mundo na prática (observe que a maioria programas Java minúsculos e de curta duração provavelmente não alocam mais do que alguns gigabytes de memória). É claro que essa JVM não vale a pena mencionar e é apenas uma coisa de brinquedo (como é essa implementação de malloc
para C). Consulte o Epsilon NoOp GC para obter mais informações. As JVMs da vida real são peças de software muito complexas e misturam várias técnicas de coleta de lixo.
Além disso, Java não é o mesmo que a JVM e você tem implementações em Java em execução sem a JVM (por exemplo , compiladores Java antecipados , tempo de execução do Android ). Em alguns casos (principalmente os acadêmicos), você pode imaginar (chamadas técnicas de "coleta de lixo em tempo de compilação") que um programa Java não aloca ou exclui em tempo de execução (por exemplo, porque o compilador otimizador foi inteligente o suficiente para usar apenas o pilha de chamadas e variáveis automáticas ).
Por que os objetos Java não são excluídos imediatamente depois que não são mais referenciados?
Porque as especificações Java e JVM não exigem isso.
Leia o manual do GC para obter mais informações (e as especificações da JVM ). Observe que estar vivo (ou útil para computação futura) de um objeto é uma propriedade de todo o programa (não modular).
O Objective-C favorece uma abordagem de contagem de referência para o gerenciamento de memória . E que também tem armadilhas (por exemplo, o Objective-C programador tem de se preocupar com referências circulares por explicitando referências fracas, mas a JVM lida com referências circulares bem na prática, sem a necessidade de atenção do programador Java).
Não há nenhuma bala de prata na programação e no design da linguagem de programação (esteja ciente do problema da parada ; ser um objeto vivo útil é indecidível em geral).
Você também pode ler SICP , Pragmática da Linguagem de Programação , o Dragon Book , o Lisp em Pequenos Pedaços e Sistemas Operacionais: Três Pedaços Fáceis . Eles não são sobre Java, mas abrirão sua mente e ajudarão a entender o que uma JVM deve fazer e como ela pode praticamente funcionar (com outras peças) no seu computador. Você também pode passar muitos meses (ou vários anos) estudando o código-fonte complexo das implementações de JVM de código aberto existentes (como o OpenJDK , que possui vários milhões de linhas de código-fonte).