ChatGPT解决这个技术问题 Extra ChatGPT

.Net 与 Java 垃圾收集器

有谁知道 Java 和 .Net 垃圾收集器之间的主要区别?网络搜索并没有透露太多,这是一个测试中出现的问题。


B
Buhake Sindi

区别在于 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 方法,它试图避免将某些分配放入伊甸园代。


很好的答案。只是事实-很好地避免了宗教战争。
-1 会关心添加一个原因吗?
值得注意的是,“普通”.net 使用一种称为“写入栅栏”的技术来跟踪自上次提升以来已写入的对象。据我了解,如果一个对象从例如 gen0 提升到 gen1,并且从那时起就没有编写过,它不可能包含对 gen0 对象的任何引用;在 gen0 收集期间,无需检查其中包含的任何引用,因为它引用的唯一对象无论如何都将被假定为“活动的”。在 gen0 收集期间跳过未写入的 gen1/gen2 对象是一个巨大的胜利。
@supercat 老实说,我希望大多数(全部?)java 世代 GC 使用相同的技术,我看不出 java 的任何特性会阻止使用它。
@ShuggyCoUk:我相信有些人会这样做,但如果有些人不这样做也不会感到惊讶,因为写栅栏不是免费的,而且由于没有它们,代 GC 可以以非常低的成本提供一些好处。如果我正在设计一个框架,我会提供一种方法来指定某些类是不可变的(包括不可变数组类型);即使是不支持写栅栏的实现也可以从知道 gen1 不可变对象不会保存对任何 gen0 对象的任何引用中受益。
B
Brian Rasmussen

这只是为了增加 ShuggyCoUk 的出色答案。 .NET GC 还使用所谓的大对象堆 (LOH)。 CLR 在 LOH 上预分配了一堆对象,并且所有用户分配的至少 85000 字节的对象也都分配在 LOH 上。此外,由于一些内部优化,在 LOH 上分配了 1000 个或更多元素的 double[]

LOH 的处理方式与分代堆不同:

它仅在完整收集期间被清理,并且永远不会像世代堆一样被压缩。

来自 LOH 的分配是通过一个空闲列表完成的,就像 malloc 在 C 运行时中处理的那样,而来自分代堆的分配基本上是通过在第 0 代中移动一个指针来完成的。

我不知道 JVM 是否有类似的东西,但它是关于如何在 .NET 中处理内存的基本信息,因此希望您会发现它很有用。


好点,通过编辑将其他扩展集成到您自己的答案中是否被认为是一种很好的形式,如果是这样,您应该使用内联还是通过评论?
现在它有一个压缩 LOH 的选项,这是默认关闭的。
压缩选项是“压缩一次”。打开它,下一个阻塞的 Gen2 集合将压缩 LOH。压缩后,该选项将恢复为关闭/默认。
J
Jason Baker

如果我没记错的话,JVM 不会像 CLR 那样将释放的内存释放回操作系统。


这是比较突出的区别之一。
d
duffymo

Java 5 对其 GC 算法进行了许多更改。

我不是 C# 专家,但这两篇文章向我表明,它们都已经从简单的标记和扫描演变为新一代模型:

http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html http://www.csharphelp.com/archives2/archive297.html


t
tobsen

我找到了这个:

在 J2SE 平台版本 1.4.2 中,有四个垃圾收集器可供选择,但在用户没有明确选择的情况下,总是选择串行垃圾收集器。在 5.0 版中,收集器的选择基于启动应用程序的机器的类别。

here 和这个

就像 JVM 管理对象的销毁一样,CLR 也通过 Mark 和 Compact 垃圾收集算法来管理对象的销毁

here

我希望这有帮助...