为什么在具有自动内存管理的语言中,人工管理甚至不被允许?我可以看出,在大多数情况下,这是不必要的,但在内存紧缺且不想依赖于智能垃圾回收器的情况下,手动管理是否有用?托管内存不能被显式释放;相反,它会自动进行垃圾回收。
为什么在具有自动内存管理的语言中,人工管理甚至不被允许?我可以看出,在大多数情况下,这是不必要的,但在内存紧缺且不想依赖于智能垃圾回收器的情况下,手动管理是否有用?托管内存不能被显式释放;相反,它会自动进行垃圾回收。
自动内存管理的编程语言旨在提供实质性的内存安全保证,这是任何手动内存管理所不能提供的。
它们可以防止以下问题:
free()
free()
指针,导致其他地方的非法访问free()
另外,自动内存管理可将活动对象移动到一个集中的区域,从而提高缓存性能,因此也可以获得更好的性能。
T
,那么内存分配器可以通过垃圾回收来保证只要该引用仍然存在,它将始终指向T
类型。更具体地说,这意味着内存分配器永远不会将该内存作为不同类型返回。free()
并使用垃圾回收,它必须确保您free()
的内存没有被其他任何人引用;换句话说,您传递给free()
的引用是该内存的唯一引用。大多数情况下,鉴于对free()
的任意调用,这种做法的成本过高,因此大多数使用垃圾回收的内存分配器都不允许这样做。调用GC.Collect
几乎总是比使用显式的free
方法更好。只有在指针/对象引用从未被引用时,才有意义地调用free
。这是一种容易出错的情况,因为有可能您会为错误类型的指针调用free
。
当运行时环境为您进行引用计数监控时,它知道哪些指针可以安全释放,哪些不行,因此让GC决定哪些内存可以释放避免了一类丑陋的错误。人们可以想象一个同时具有GC
和free
的运行时实现,在这个实现中,显式调用free
来释放单个内存块可能比运行完整个GC.Collect
要快得多(但不要期望手动释放每个可能的内存块比GC更快)。但我认为C#、CLI(以及其他具有垃圾收集器的语言,如Java)的设计者已经决定在这里优先考虑健壮性和安全性而不是速度。
有趣的是,你可以通过 System.GC 访问垃圾回收器——尽管从我所读到的一切来看,强烈建议您允许 GC 自行管理。
曾经有第三方供应商建议我使用以下两行代码来处理 DLL 或 COM 对象等垃圾回收问题:
// Force garbage collection (cleanup event objects from previous run.)
GC.Collect(); // Force an immediate garbage collection of all generations
GC.GetTotalMemory(true);
我不能说这是“答案”,但我想到的一个可能原因是,如果你可以使用free
,你可能会意外地双倍释放指针/引用,甚至更糟糕的是,在释放后继续使用。这违背了使用c#/java等语言的主要目的。
当然,解决这个问题的一个可能方法是,让你的free
通过引用来接收参数,并在释放后将其设置为null
。但是,如果他们像这样传递一个r-value
: free(whatever())
,该怎么办呢?我想你可以为r-value版本提供重载,但我甚至不知道c#是否支持这样的东西:-P。
最后,即使这样也是不够的,因为正如已经指出的那样,你可以有多个引用指向同一个对象。将其中一个设置为null
并不能防止其他引用访问现在已被释放的对象。
如果你处于“不想依赖GC聪明”的情况下,那么很可能你选择的框架不正确。在.NET中,你可以稍微操纵GC(http://msdn.microsoft.com/library/system.gc.aspx),在Java中不确定。
我认为你不能称之为免费,因为你开始执行GC的一个任务。当GC以它认为最好的方式进行操作并在它决定时执行操作时,GC的效率可以得到保证。如果开发人员干预GC,它的整体效率可能会降低。
许多其他答案提供了关于垃圾回收如何工作以及在针对提供垃圾回收的运行时系统进行编程时应该如何思考的好解释。
我想添加一个技巧,当我在使用垃圾回收语言编程时,我尽量铭记在心的规则是:“尽早放弃指针是很重要的。” 通过放弃指针,我的意思是不再指向我将不再使用的对象。例如,在某些语言中,可以通过将变量设置为Null来实现这一点。这可以被视为给垃圾回收器的提示,表明它可以收集此对象,前提是没有其他指向它的指针。
free()
呢?假设您有一大块内存需要释放。free()
来摆脱它,而不能使用垃圾收集器,则仍然可以访问该块(如果语言具有概念,则不通过弱指针),这意味着您留下了该语言等效的悬空指针。free()
,或修改其含义,使其不再有用。free
函数会释放由指针指向的内存块并将其返回给内存管理器。垃圾回收语言和虚拟机使用更抽象的引用概念代替指针。大多数生产环境中的垃圾回收器都是移动式的,这意味着高级代码持有值或对象的引用,但底层内存位置可以在不知情的情况下被虚拟机移动。这用于压缩堆,防止碎片化并提高局部性。
因此,在具有垃圾回收功能时没有free
的好理由。
Wizbang
调用Dispose
可能会将其转换为无用的Wizbang
对象,该对象不能再执行任何特定于Wizbang
的操作,但它仍然是一个有效的Object
,并且像GetType
、Equals
等方法应该继续工作。只要任何引用仍然指向Wizbang
,所有对它的引用都将成为指向死亡Wizbang
的引用。相比之下,在手动分配系统中,对存在其他副本的指针调用free
可能会导致这些其他副本变成指向完全不同的东西的引用。 - supercat