您可以创建新对象,但是当您使用它们时,也没有真正的方法可以立即销毁它们吗?
为什么每个OOP运行时都没有实现这样的行为?
我确信我们开发人员可以(通常)组织对象实例在我们使用完毕后进行销毁。
function work(){
var p1:Point = new Point(x, y);
var p2:Point = new Point(x2, y2);
....
destroy p1;
destroy p2;
}
答案 0 :(得分:9)
从.NET说起,答案就是记忆安全。
考虑两个项目A和B(对象或方法)都持有对象X的引用
现在A做destroy X;
。然后B留下无效的引用。这是非托管语言中的常见错误模式。删除手动销毁可防止这种情
但同样重要的问题是:它会有多大帮助吗?答案是不。短暂的内存在.NET中非常便宜。你提议的破坏不具有任何价值。
答案 1 :(得分:5)
简而言之,因为这通常使编程任务复杂化。手动内存管理需要相当多的技能和努力才能正确使用 - 您无法将精力用于您要解决的实际任务。
您在上面展示的场景很常见,但远非唯一的场景。如果您返回对其中一个对象的引用怎么办?如果您传递对被调用方法的引用(可能存储它的位置),该怎么办?等等。在您负责任地销毁对象之前,这些都是您需要考虑的问题。这些被称为“所有权”。
硬币的另一面是,在执行过程中能否在指定点摧毁物体真的会产生积极影响吗?这使得析构函数和C ++中的RAII成为可能,这是一个非常强大的习惯用法。 Java没有它,当我开始使用Java时,我经常错过它。但是,有一些方法可以在Java中有效地解决这些问题(例如finally
块)。无论优雅的RAII如何,它仍然无法支付手动内存管理可能导致的整个混乱。
然后你可能会建议,“为什么我们不能同时拥有:在我想要时显式销毁对象,以及其余的垃圾收集?”。你可以在编译器编写者和JVM实现者得到你之前开始运行求助:-)这会使事情变得如此复杂,如果没有真正巨大的实际好处,没有人会这样做。手动内存管理不提供这样的东西。
答案 2 :(得分:2)
不,不,不。 Java / C#为你提供的最好的东西之一就是内存管理 - 如果你必须自己处理它,那么它更容易出错,如果人们有可能会使用和滥用它会造成越来越多的错误和内存泄漏要么忘记解除分配,要么过早做。在不考虑内存管理的情况下,设计/编写大型项目非常困难。
答案 3 :(得分:2)
并非所有OO语言都具有垃圾收集(Java)或显式内存释放(C ++)的原因是在每种语言的设计中选择的策略的结果。 Java不允许程序员明确地分配和释放内存。相反,程序员在
时处理引用变量Point p = new Point(x,y);//p is a reference variable
并且p的解除分配是通过垃圾收集(自动)完成的。 为了进行垃圾收集,您选择显式符号引用而不使用指针。因此,C ++没有垃圾收集,并且不能将其作为语言的固有功能提供。程序员必须使用
明确地释放内存delete p;
或者编写自己的垃圾收集实现。因此,根据OO语言的设计,您可以进行垃圾收集或手动释放。你不能兼得。
答案 4 :(得分:1)
C ++是一种OOP语言;它提供了可用于构造对象的'new'关键字和可用于销毁对象的'delete'关键字。如果不小心使用,删除对象在C ++中可能会产生灾难性的影响;如果单个对象有两个引用它的指针,并且您从其中一个指针中删除该对象,则另一个指针变为无效,并且任何使用它的尝试都将是未定义的行为(通常程序将尝试使用该内存位置中的值;可能已经被运行时重新分配用于其他目的)
答案 5 :(得分:1)
对于Java,请参阅Runtime.gc()。
对于C#,请参阅System.GC.Collect
我不完全确定C#,但在Java中你只能请求垃圾收集发生,但是否真正清理未使用的引用的决定由虚拟机决定
关于C ++风格的内存管理与解释语言中的垃圾收集是否表现更好有很多争论,但如果你正在做Java或C#工作,我会怀疑你是否真的需要强制垃圾收集和一般来说,如果你来自C ++我会建议抵制管理内存的诱惑,并让VM优化为你做。您应该确保已经释放了对未使用的对象的所有引用,以便可以进行垃圾回收。我不担心何时。
答案 6 :(得分:1)
您可以在大多数语言中将现有引用设置为null或类似,然后允许运行时根据需要对其进行垃圾回收。
我想你付出的代价是为了让你的系统能够让你的记忆变得更加便宜,那么当你想要自己失去很多能力的时候