Je suis assez vieux J'y suis allé et l'ai vu et me suis cogné la tête à plusieurs reprises.
J'étais à une conférence à Hursley Park où les garçons d'IBM nous disaient à quel point ce nouveau langage Java était merveilleux. Seule une personne a demandé ... pourquoi n'y a-t-il pas de destructeur pour ces objets? Il ne voulait pas dire ce que nous savons en tant que destructeur en C ++, mais il n'y avait pas non plus de finaliseur (ou il avait des finaliseurs mais ils ne fonctionnaient pas fondamentalement). Cela fait longtemps, et nous avons décidé que Java était un langage de jouet à ce moment-là.
maintenant, ils ont ajouté les finaliseurs aux spécifications de langage et Java a été adopté.
Bien sûr, plus tard, on a dit à tout le monde de ne pas mettre de finaliseurs sur leurs objets car cela ralentissait énormément le GC. (car il fallait non seulement verrouiller le tas, mais aussi déplacer les objets à finaliser dans une zone temporaire, car ces méthodes ne pouvaient pas être appelées car le GC avait suspendu l'exécution de l'application. Au lieu de cela, elles seraient appelées immédiatement avant la prochaine Cycle GC) (et pire encore, le finaliseur n’était jamais appelé du tout lorsque l’application était en train de s’arrêter. Imaginez que votre fichier ne soit pas fermé, jamais)
Ensuite, nous avons eu C #, et je me souviens du forum de discussion sur MSDN où on nous a dit à quel point ce nouveau langage C # était merveilleux. Quelqu'un a demandé pourquoi il n'y avait pas de finalisation déterministe et les gars de la SP nous ont dit que nous n'avions pas besoin de telles choses, puis nous ont dit que nous devions changer notre façon de concevoir les applications, puis nous ont dit à quel point le GC était incroyable et toutes nos anciennes applications. ordures et jamais travaillé à cause de toutes les références circulaires. Ensuite, ils ont cédé à la pression et nous ont dit qu'ils avaient ajouté ce modèle IDispose à la spécification que nous pouvions utiliser. Je pensais que c'était à peu près le retour à la gestion de mémoire manuelle pour nous dans les applications C # à ce stade.
Bien sûr, les gars de la SP ont découvert plus tard que tout ce qu'ils nous avaient dit était… eh bien, ils ont fait qu'Idispose était un peu plus qu'une simple interface standard, et ils ont ensuite ajouté la déclaration using. W00t! Ils ont compris que la finalisation déterministe était quelque chose qui manquait dans la langue après tout. Bien sûr, vous devez toujours vous rappeler de le mettre partout, donc c'est toujours un peu manuel, mais c'est mieux.
Alors, pourquoi l'ont-ils fait alors qu'ils auraient pu dès le départ placer une sémantique de style utilisateur dans chaque bloc de portée? Probablement l'efficacité, mais j'aime penser qu'ils ne se sont pas rendus compte. Tout comme finalement, ils se sont rendu compte que vous aviez encore besoin de pointeurs intelligents dans .NET (google SafeHandle), ils pensaient que le GC résoudrait réellement tous les problèmes. Ils ont oublié qu'un objet est plus qu'une simple mémoire et que le CPG est principalement conçu pour gérer la gestion de la mémoire. ils ont été pris au dépourvu par l'idée que le GC s'en chargerait et ont oublié que vous y mettiez d'autres éléments, un objet n'est pas simplement une goutte de mémoire qui n'a pas d'importance si vous ne le supprimez pas pendant un certain temps.
Mais je pense aussi que l’absence de méthode de finalisation dans le langage Java d’origine avait quelque chose de plus important: les objets que vous avez créés étaient tous liés à la mémoire, et si vous vouliez supprimer autre chose (comme un descripteur de base de données, un socket ou autre). ) alors vous deviez le faire manuellement .
Rappelez-vous que Java a été conçu pour les environnements embarqués où les utilisateurs étaient habitués à écrire du code C avec beaucoup d'allocations manuelles. Par conséquent, le fait de ne pas avoir la gratuité automatique n'était pas un problème - ils ne l'avaient jamais fait auparavant, alors pourquoi en auriez-vous besoin en Java? Le problème n'avait rien à voir avec les threads, ou pile / tas, il était probablement juste là pour faciliter l'allocation de mémoire (et donc le dé-allouer). En tout, l'instruction try / finally est probablement un meilleur endroit pour gérer les ressources non-mémoire.
Donc, IMHO, la façon dont .NET a simplement copié le plus gros défaut de Java est sa plus grande faiblesse. .NET aurait dû être un meilleur C ++, pas un meilleur Java.