A деструктор не имеет прямого отношения к освобождению памяти - вместо этого это «ловушка», позволяющая запускать пользовательский код, когда объект пригоден для восстановления. То есть это противоположность конструктору - конструктор не выделяет память (как это делает GC до вызова конструктора), и, таким образом, деструктор не освобождает память (как будет сделано GC впоследствии).
Несмотря на то, что ГХ может отлично управлять собственными ресурсами (например, другими объектами и графами объектов), внешние ресурсы, такие как файловые дескрипторы, все равно должны быть "удалены вручную". Например, представьте себе класс MyFile, где деструктор будет гарантировать, что файл, если он открыт, будет закрыт, - хотя, пожалуй, «лучше» установить требование вызывать операцию Close / Dispose над объектом, деструктор может быть в этом случае используется как резервный механизм.
Я бы поспорил против общего использования деструкторов в языках с GC. Есть ряд тонких проблем, которые они могут представить, таких как явный недетерминизм и возможность случайного сохранения объектов - даже в таких языках, как PHP, которые используют подсчет ссылок. (В моделях Java / JVM и .NET используются финализаторы, которые еще более привередливы.)
Удачного кодирования.