有谁知道 Java 和 .Net 垃圾收集器之间的主要区别?网络搜索并没有透露太多,这是一个测试中出现的问题。
区别在于 CLR (.Net) GC 和 JVM GC 而不是语言本身。两者都可能发生变化,并且它们的行为规范松散,以允许对其进行更改而不影响程序的正确性。
有一些历史差异主要是由于 .Net 的设计借鉴了 java(和其他基于 gc 的平台)的演变。在下文中,不要假设 .Net 在某种程度上优于它,因为它从一开始就包含功能,它只是后来出现的结果。
一个显着的公开可见的区别是 MS GC 暴露了它的代际性质(通过 GC api),这可能会在一段时间内保持正确,因为这是基于大多数程序表现出的行为的明显方法:大多数分配都非常短暂的。
最初的 JVM 没有分代垃圾收集器,尽管这个特性被迅速添加。 SunOracle 和其他人实现的第一代收集器往往是 Mark and Sweep。人们意识到标记-扫描-压缩方法将导致更好的内存局部性,从而证明额外的复制开销是合理的。 CLR 运行时以这种行为首次亮相。
SunOracle 和 Microsoft 的 GC 实施“精神”之间的区别之一是可配置性。
Sun 提供了大量选项(在命令行中)来调整 GC 的各个方面或在不同模式之间切换。许多选项都属于 -X 或 -XX 以表明它们缺乏跨不同版本或供应商的支持。相比之下,CLR 几乎没有提供可配置性。您唯一真正的选择是使用分别针对吞吐量和延迟进行优化的服务器或客户端收集器。
两家公司(以及开源实现)都在积极研究 GC 策略作为 pre-tenuring 方法,它试图避免将某些分配放入伊甸园代。
这只是为了增加 ShuggyCoUk 的出色答案。 .NET GC 还使用所谓的大对象堆 (LOH)。 CLR 在 LOH 上预分配了一堆对象,并且所有用户分配的至少 85000 字节的对象也都分配在 LOH 上。此外,由于一些内部优化,在 LOH 上分配了 1000 个或更多元素的 double[]
。
LOH 的处理方式与分代堆不同:
它仅在完整收集期间被清理,并且永远不会像世代堆一样被压缩。
来自 LOH 的分配是通过一个空闲列表完成的,就像 malloc 在 C 运行时中处理的那样,而来自分代堆的分配基本上是通过在第 0 代中移动一个指针来完成的。
我不知道 JVM 是否有类似的东西,但它是关于如何在 .NET 中处理内存的基本信息,因此希望您会发现它很有用。
如果我没记错的话,JVM 不会像 CLR 那样将释放的内存释放回操作系统。
Java 5 对其 GC 算法进行了许多更改。
我不是 C# 专家,但这两篇文章向我表明,它们都已经从简单的标记和扫描演变为新一代模型:
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html http://www.csharphelp.com/archives2/archive297.html
不定期副业成功案例分享