Eu sou bem velha. Eu estive lá e vi isso e bati minha cabeça sobre isso muitas vezes.
Eu estava em uma conferência no Hursley Park, onde os rapazes da IBM estavam nos dizendo como essa nova linguagem Java era maravilhosa, apenas alguém perguntou ... por que não há um destruidor para esses objetos? Ele não quis dizer aquilo que conhecemos como um destruidor em C ++, mas também não havia nenhum finalizador (ou tinha finalizadores, mas eles basicamente não funcionavam). Isso está de volta, e decidimos que Java era uma linguagem de brinquedo naquele momento.
agora eles adicionaram Finalisers à especificação de idioma e o Java viu alguma adoção.
É claro que depois foi dito a todos que não colocassem os finalizadores em seus objetos porque isso reduziu a velocidade do GC tremendamente. (como era necessário não apenas bloquear o heap, mas também mover os objetos para serem finalizados para uma área temporária, pois esses métodos não poderiam ser chamados porque o GC pausou a execução do aplicativo. Em vez disso, eles seriam chamados imediatamente antes do próximo GC cycle) (e pior, às vezes o finalizador nunca seria chamado quando o aplicativo estava sendo desligado. Imagine não ter seu identificador de arquivo fechado, nunca)
Em seguida, tivemos o C # e lembro-me do fórum de discussão no MSDN, onde nos foi dito como essa nova linguagem C # era maravilhosa. Alguém perguntou por que não havia finalização determinista e os garotos do MS nos disseram como não precisávamos de tais coisas, depois nos disseram que precisávamos mudar nossa maneira de projetar aplicativos, depois nos disseram como a GC era incrível e como todos os nossos aplicativos antigos eram lixo e nunca funcionou por causa de todas as referências circulares. Então eles cederam à pressão e nos disseram que haviam acrescentado esse padrão IDispose às especificações que poderíamos usar. Eu pensei que era praticamente de volta ao gerenciamento de memória manual para nós em aplicativos C # naquele momento.
Naturalmente, os meninos da MS descobriram mais tarde que tudo o que eles nos disseram era ... bem, eles fizeram IDispor um pouco mais do que apenas uma interface padrão, e mais tarde adicionaram a declaração using. W00t! Eles perceberam que a finalização determinista era algo que faltava na língua, afinal. Claro, você ainda tem que lembrar de colocá-lo em todos os lugares, então ainda é um pouco manual, mas é melhor.
Então, por que eles fizeram isso quando poderiam ter semânticas no estilo de uso colocadas automaticamente em cada bloco de escopo desde o início? Provavelmente eficiência, mas gosto de pensar que eles simplesmente não percebem. Assim como eventualmente eles perceberam que você ainda precisa de ponteiros inteligentes no .NET (google SafeHandle) eles achavam que o GC realmente resolveria todos os problemas. Eles esqueceram que um objeto é mais do que apenas memória e que o GC é projetado principalmente para gerenciar o gerenciamento de memória. eles ficaram presos na idéia de que o GC lidaria com isso, e esqueceram que você colocou outras coisas lá, um objeto não é apenas uma bolha de memória que não importa se você não o excluir por um tempo.
Mas eu também acho que a falta de um método finalize no Java original tinha um pouco mais - que os objetos que você criava eram tudo sobre memória, e se você quisesse apagar alguma outra coisa (como um manipulador DB ou um soquete ou qualquer outra coisa), então era esperado que você fizesse manualmente .
Lembre-se de que o Java foi projetado para ambientes incorporados onde as pessoas estavam acostumadas a escrever código C com muitas alocações manuais, portanto, não ter acesso automático não era um grande problema - nunca o fizeram antes, então por que você precisa dele? Java? O problema não tem nada a ver com threads, ou stack / heap, ele provavelmente estava lá apenas para facilitar a alocação de memória (e, portanto, desalocar). No geral, a instrução try / finally é provavelmente um lugar melhor para lidar com recursos que não são de memória.
Então IMHO, a maneira com que o .NET simplesmente copiou a maior falha de Java é sua maior fraqueza. O .NET deveria ter sido um C ++ melhor, não um Java melhor.