为什么一些垃圾收集的面向对象编程语言没有析构函数?

esyap4oy  于 2021-07-08  发布在  Java
关注(0)|答案(2)|浏览(427)

考虑下面的情况
当我们在类中使用c api来创建一些数据时,这些数据是使用malloc在堆中分配的(例如 Object* create_obj() ),我们必须调用某个方法( void free_obj() )在类生存期结束时手动释放内存。
当一种语言有一个析构函数时,我们可以很容易地把 free_obj 在类析构函数中,这样用户就不必调用 free_obj 并等待类被垃圾回收。
我的问题
为什么一些垃圾收集&oop编程语言(java[java]一直不赞成它是 finalize ]还有ruby)没有析构函数?
当你像上面那样连接一个低级api时,析构函数不是必须的吗?如果没有必要,解决以下问题的最佳实践是什么?

wa7juj8i

wa7juj8i1#

析构函数在基于分配的语言中是必需的,但在ruby等gc语言中是可选的。析构函数模式不能与垃圾收集混淆,正如您所说的,它代表了将对象寿命与作用域相匹配。
对象存在一段时间,然后所述对象消耗的内存部分被标记为可用于将来的对象。ruby提供两组内存: malloc heap 以及 Ruby object heap . malloc heap 除非ruby在gc结束时未使用内存,否则不会释放回操作系统。后者(一个 malloc heap )是大多数ruby对象生活的地方。ruby垃圾收集器将其焦点指向这里并经常清理,这意味着大部分情况下,析构函数是不必要的。并不是每个对象都会被收集,但是像ruby这样的语言不能保证这一点。
在ruby中,变量引用一个对象,这意味着一个对象存储在某个地方,变量只保存对象id。如果我们调用一个析构函数来处理一个被另一个变量收集或析构函数的对象,它将返回 nil 但可能是相同的对象id,这可能会导致运行时出现问题。
鲁比的 define_finalizer 这不是常见的做法,因此不鼓励开发人员使用它。方法不能引用它正在释放的对象,因为回调是在对象被释放后执行的,所以不能保证它会被调用。如果 finalizer proc保留引用 self 这将使对象不可能被垃圾收集,这意味着它永远不会被收集。

67up9zun

67up9zun2#

像java和ruby这样的语言有终结器,但没有析构函数。主要原因是确定性破坏以语言设计者不希望的方式限制了实现。
现代高性能垃圾收集器采用的许多性能技巧在确定性终结时都是不可能的。ruby和java甚至不能保证对象被收集。ruby或java实现从不收集对象是完全合法的,即使对象是不可访问的。
即使是具有非常简单的垃圾收集器的cpython也不能保证确定性终结。它只保证非循环对象图的确定性终结。python社区已经明确表示,这是cpython的私有内部实现细节,而不是python语言语义的一部分,这意味着其他实现(例如pypy、ironpython、jython)不必实现它,因此可以自由地实现更好的垃圾收集器。

相关问题