为什么Java没有像C ++这样的析构函数?

Java有自己的垃圾收集实现,因此它不需要像C ++这样的任何析构函数。 这使得Java开发人员懒得实现内存管理。

我们仍然可以使用析构函数和垃圾收集器,开发人员可以在其中释放资源并且可以节省垃圾收集器的工作。 这可能会提高应用程序的性能。 为什么Java不提供任何析构函数的机制?

开发人员无法控制GC,但他/她可以控制或创建对象 。 那为什么不给它们破坏物体的能力呢?

你断言“垃圾收集非常昂贵” – 你能用证据支持吗? 垃圾收集当然不是免费的,但现代垃圾收集器非常好。

请注意,GC能够高效的方法之一是它知道它是进行内存分配和释放(对于托管对象)的唯一方法。 允许开发人员明确释放对象可能会妨碍这种效率。 您还需要担心如果开发人员试图“使用”一个释放的对象会发生什么:

Foo f = new Foo(); Foo g = f; free(f); // Or whatever System.out.println(g.toString()); // What should this do? 

您是否建议每个对象都应该有一个额外的标志“是否已明确释放”需要在每次取消引用时进行检查? 说实话,这就像是一场灾难。

你是对的 – 它确实允许Java开发人员在这方面懒惰。 这是好事。 IDE也允许开发人员变得懒惰 – 高级语言也是如此。等内存分配的懒惰使得托管环境中的开发人员能够花费精力来解决业务问题而不是内存管理。

垃圾收集非常昂贵。

事实上,对于复杂的应用程序,垃圾收集的性能基于malloc / free手动存储管理相比具有竞争力 。 Benjamin Zorn有一篇经典论文清楚地certificate了这一点。 在本文中,Zorn描述了他如何修改一些大型密集型应用程序以使用保守的垃圾收集器而不是mallocfree 。 然后他对应用程序的原始版本和修改版本进行了基准测试。 结果是相当的表现。

本文发表于1993年的软件实践与经验。如果你还没有阅读,你就没有资格就垃圾收集的“低效率”发表声明。

请注意,这项研究是在1993年的老式保守垃圾收集器中完成的。 一个保守的collections家是没有任何压缩的标记扫描; 即非垃圾对象不移动。 后者意味着为新对象分配空间与malloc一样缓慢和复杂。 相比之下,现代垃圾收集器(例如Java 6/7)是分代式复制收集器,效率更高。 由于复制压缩了剩余的非垃圾对象,因此分配速度要快得多。 这使GC更具竞争力……如果有人能找到比较的方法。


开发人员无法控制GC,但他/她可以控制或创建对象。 那为什么不给它们破坏物体的能力呢?

这取决于“毁灭”的确切含义。

  • 在Java中,您可以分配null 。 在某些情况下,这可能会加速对象的破坏。

  • 在Java中,您可以使用终结器和Reference类型来注意对象即将被销毁……以及它的某些内容。

  • 在Java中,您可以在任何对象上定义close() (或等效)方法,并让它执行适当的操作。 然后明确地调用它。

  • 在Java 7中,您具有“try with resources”构造,用于在作用域出口上的资源上自动调用close()

但是,您现在无法删除Java对象。 这是不允许的原因是它允许程序创建悬空引用,这可能导致堆的损坏和随机JVM崩溃。

这不是Java方式。 理念是编写可靠的程序比效率更重要。 虽然Java的某些方面不遵循这一点(例如线程),但没有人想要随机JVM崩溃的可能性。

C ++析构函数不是一种破坏对象的方法 – 它是在对象被破坏时要完成的一组操作。 在Java中,您无法控制对象被破坏的时间(它们甚至可能永远不会被破坏),因此强烈建议不要在对象破坏时执行任何重要代码(尽管可能 – finalize方法)。 如果你不是要求析构函数,而是要求一种明确销毁给定对象的方法,那么你就是在你的代码中引用悬空引用。 他们不受欢迎。

这使得Java开发人员懒得实现内存管理。

不,它会释放它们以执行有用的工作。

而垃圾收集非常昂贵。

什么相比? 事实呢? 数据? 你对这句话已经过了20年了。 仅仅采用Java就有效地反驳了这种争论。

这可能会提高应用程序的性能。

或不。 你有一些事实可以引用吗?

那为什么不给它们破坏物体的能力呢?

因为它不是必需的?

在C ++ 中销毁对象时调用析构函数, 而不是销毁对象。 如果要保证清理,请让用户调用Destroy方法或类似方法。

如果你知道你不再使用某些大对象,只需将它们的引用设置为null即可。 这可能会加速这些对象的垃圾收集。

C ++析构函数不是一种破坏对象的方法 – 它是在对象被破坏时要完成的一组操作。

我认为你的术语令人困惑。 我是这样看的:

create object =首先分配内存,然后通过构造函数构造

destroy object = first destruct via destructor,然后释放内存

如何分配和释放内存取决于。 如果使用newdelete ,则内存管理由void* operator new(size_t)void operator delete(void*)

C ++析构函数可用于释放对象拥有的任何资源,而不仅仅是内存。 它可能是文件,套接字,互斥锁,信号量或任何其他资源句柄。 使用析构函数是防止资源泄漏的明智方法。 将资源处理包装在C ++类中,并创建一个释放任何已分配资源的析构函数。 我在Java中没有看到任何这样的方法。 您必须显式释放资源,如果有许多可能的退出路径,这可能会很棘手。

不,java不支持析构函数。 所有释放内存任务都由GARBAGE COLLECTOR完成。

Java使用垃圾收集器拥有自己的内存管理function。 当您使用finalize()时,该对象可用于垃圾回收,您不需要显式调用析构函数。 C#和Java不希望你担心析构函数,因为它们具有垃圾收集function。

Java是一种字节码语言,它具有非常强大的垃圾检测function。 如果你允许人们定义他们自己的析构函数,他们可能会犯一些错误。 通过自动化该过程,Java打算防止这些错误。

您确实能够在Java中控制对象销毁。 它只是使用不同的习语:

 Connection conn = null; try { conn = ... // do stuff } finally { try { conn.close(); } catch (Exception e) { } } 

你可以在这一点上指出这不是对象破坏,例如,你可以将该对象传递给其他东西,并且仍然可以引用它。 你是对的。 它就像Java(和大多数托管平台)一样接近。

但是,正如你所说,没有Java没有像C ++那样的析构函数机制。 有些人误认为终结者。 它们不是破坏者,使用它们是危险的。

程序员的内存管理很难。 您可以轻松泄漏内存,尤其是在执行multithreading编程时(也很难)。 经验表明,在绝大多数情况下,GC的成本虽然是实际的,有时是实质性的,但在生产力提高和错误发生方面是完全合理的,这就是为什么绝大多数平台现在都是“管理”的(这意味着它们使用)垃圾收集)。