为什么一些垃圾回收和OOP编程语言没有析构函数?



考虑以下情况

当我们在类中使用C API来创建一些使用malloc(例如Object* create_obj()(在堆中分配的数据时,我们必须在类生命周期结束时调用某个方法(void free_obj()(来手动释放内存。

当一种语言有析构函数时,我们可以很容易地将free_obj放在类析构函数中,这样用户就不必手动调用free_obj并等待类被垃圾收集。

我的问题

  • 为什么收集了一些垃圾&OOP编程语言(Java[Java一直在贬低它是finalize]和Ruby(没有析构函数?

  • 当你接口一个低级别的API时,析构函数不是必要的吗?如果没有必要,解决以下问题的最佳做法是什么?

Java和Ruby等语言有终结器,但没有析构函数。主要原因是确定性破坏以语言设计者不想做的方式限制了实现

现代高性能垃圾收集器所采用的许多性能技巧在确定性终结的情况下是不可能的。Ruby和Java甚至根本不能保证对象会被收集。Ruby或Java实现从不收集对象是完全合法的,即使它是不可访问的。

即使是CPython,它有一个非常简单的垃圾收集器,也不能保证确定性的终结。它只保证非循环对象图的确定性终结。Python社区已经明确表示,这是CPython的私有内部实现细节,而不是Python语言语义的部分,这意味着其他实现(例如PyPy、IronPython、Jython(不必实现它,因此可以自由实现更好的垃圾收集器。

析构函数在基于分配的语言中是必要的,但在Ruby等GC语言中是可选的。析构函数模式不能与垃圾收集混淆,正如您所说,它代表了将对象寿命与范围相匹配。

对象存在一段时间,然后所述对象消耗的内存部分被标记为可用于未来的对象。Ruby提供了两组内存:malloc heapRuby object heapmalloc heap不会释放回操作系统,除非Ruby在gc结束时未使用内存。后者(malloc heap的子集(是大多数Ruby对象所在的地方。Ruby垃圾收集器将重点放在这里,并经常进行清理,这意味着在大多数情况下,析构函数是不必要的。并不是每个对象都会被收集,但像Ruby这样的语言并不能保证这一点。

在Ruby中,变量引用一个Object,这意味着一个Object存储在某个地方,变量只保存Object id。如果我们对另一个变量收集或销毁的对象调用析构函数,它将返回nil,但可能相同的对象id,这可能会在运行时引发问题。

Ruby的define_finalizer不是常见的做法,开发人员不鼓励使用它。该方法不能引用它正在释放的对象,因为回调是在对象释放后执行的,所以不能保证它会被调用。如果一个finalizer进程拥有对self的引用,这将使对象不可能被垃圾收集,这意味着它永远不会被收集。

最新更新