大多数程序员都认为垃圾收集是一件很棒的事情,在大多数应用程序中,这种开销是非常值得的。然而,我个人的观察是,大多数对象的内存管理都是微不足道的,通常可能有10%-20%的内存管理需要引用计数和真正复杂的内存管理方案。在我看来,通过保守地手动删除对象生命周期明显的大型对象,并让GC收集其余的对象,只要GC实现支持这样的事情,就可以用很小的开销获得垃圾收集的所有好处。这将允许GC运行频率更低,消耗更少的多余内存,同时仍然避免实际难以手动管理的情况。更有趣的是,如果编译器在生命周期明显的地方自动插入确定性的delete语句:
int myFunc() {
Foo[] foo = new Foo[arbitraryNumber]; // May be too big to stack allocate.
// do stuff such that the compiler can prove foo doesn't escape.
// foo is obviously no longer needed, can be automatically deleted here.
return someInteger;
}当然,这可能不适用于复制GC,但为了这篇文章,让我们假设GC没有复制。为什么这种混合内存管理方案在主流编程语言中显然如此罕见?
发布于 2009-02-12 15:23:46
因为这种情况太罕见了。几乎没有一种方法是孤立的。它们都接受来自外部的对象,或者创建对象并将其传递出去。
一个不访问任何字段,没有参数,不返回任何东西的方法不能做任何事情。
相反,GC专注于最常见的情况( 90%),并试图控制这90% (寿命较短的临时对象)。这意味着在一般情况下,您需要检查的对象较少,其余的都无关紧要。接下来,使用增量扫描(这样您就可以在小冲刺中运行,这些冲刺只会中断很短的时间)。
我曾经试图想出一个更好的GC算法,但失败得很惨烈。他们使用了一种近乎神秘的方法。这篇关于Java 5 GC Performance Tuning的文档应该会给你一些启发。当然还有GC article in Wikipedia。
归根结底:使用GC甚至可以比使用传统的内存分配和释放模式更快。想想经典的算法,它只是定位任何可到达的对象,并将其复制到新的位置。如果您刚刚忘记了一大堆对象(比如,所有已分配对象的90% ),此算法只需检查其余的(10%)。任何它达不到的东西,不管有多多,都无关紧要。现在你可能会说复制是昂贵的,但a)这不是真的;今天一个普通的桌面CPU可以在不到100ms的时间内复制40MB;b)复制将保护您不受碎片的影响,所以这实际上是一件好事。
发布于 2009-02-12 15:57:10
“大多数程序员都认为垃圾收集是一件很棒的事情,在大多数应用程序中,这种开销是非常值得的。”
概括性的概括。
发布于 2009-02-12 15:18:42
关于“显然不再需要”的快速说明:这不是那么容易;)
[...]
Foo() {
someGlobalList.add(this);
}
[...]除此之外,你可以手动删除大的东西的想法是一个很好的想法。据我所知,它至少部分是在现代语言中实现的(例如C#中的using,遗憾的是它实际上并不是免费的)。然而,并没有达到你所希望的程度。
https://stackoverflow.com/questions/541694
复制相似问题