量化垃圾回收与显式内存管理的性能

2022-09-02 10:04:39

我在这里找到了这篇文章:

量化垃圾回收与显式内存管理的性能

http://www.cs.umass.edu/~emery/pubs/gcvsmalloc.pdf

在结论部分,它的内容如下:

通过比较一系列基准测试的运行时、空间消耗和虚拟内存占用,我们发现,当给定足够的内存时,性能最佳的垃圾回收器的运行时性能与显式内存管理具有竞争力。特别是,当垃圾回收的内存量是所需内存的五倍时,其运行时性能与显式内存管理的内存性能相当或略高于显式内存管理。但是,当垃圾回收必须使用较小的堆时,其性能会大幅下降。内存量是原来的三倍,平均运行速度要慢 17%,内存是内存的两倍,运行速度会慢 70%。当物理内存稀缺时,垃圾回收也更容易分页。在这种情况下,我们在此处检查的所有垃圾回收器都会遭受与显式内存管理相关的数量级性能损失。

因此,如果我的理解是正确的:如果我有一个用本机C++编写的应用程序需要100 MB的内存,那么要使用“托管”(即基于垃圾回收器)的语言(例如Java,C#)实现相同的性能,该应用程序应该需要5 * 100 MB = 500 MB?(如果 2*100 MB = 200 MB,托管应用的运行速度将比本机应用慢 70%?

您是否知道当前(即最新的Java VM和.NET 4.0)垃圾回收器是否遇到上述文章中描述的相同问题?现代垃圾回收器的性能是否得到改善?

谢谢。


答案 1

如果我有一个用本机C++编写的应用程序需要100 MB的内存,为了使用“托管”(即基于垃圾回收器)语言(例如Java,C#)实现相同的性能,该应用程序应该需要5 * 100 MB = 500 MB?(如果 2*100 MB = 200 MB,托管应用的运行速度将比本机应用慢 70%?

仅当应用在分配和释放内存方面遇到瓶颈时。请注意,本文专门讨论了垃圾回收器本身的性能。


答案 2

你似乎在问两件事:

  • 自该研究以来,GC是否有所改善,并且
  • 我可以用论文的结论作为预测所需记忆的公式。

第一个问题的答案是,GC算法没有重大突破会使一般结论无效:

  • GC 的内存管理仍需要显著增加虚拟内存。
  • 如果尝试限制堆大小,则 GC 性能会显著下降。
  • 如果实际内存受到限制,则由于分页开销,GC 的内存管理方法会导致性能显著降低。

但是,结论不能真正用作公式:

  • 最初的研究是用JikesRVM而不是Sun JVM完成的。
  • 自研究以来,Sun JVM的垃圾收集器在大约5年内有所改善。
  • 该研究似乎没有考虑到Java数据结构比等效C++数据结构占用更多的空间,原因与GC无关。

关于最后一点,我看到有人在谈论Java内存开销的演讲。例如,它发现Java字符串的最小表示大小约为48字节。(String 由两个基元对象组成;一个是具有 4 个字大小字段的对象,另一个是至少包含 1 个字内容的数组。每个基元对象还有 3 或 4 个单词的开销。Java集合数据结构同样使用比人们意识到的更多的内存。

这些开销本身与 GC 无关。相反,它们是Java语言,JVM和类库中设计决策的直接和间接后果。例如:

  • 每个 Java 基元对象标头1 保留一个单词作为对象的“标识哈希码”值,保留一个或多个单词用于表示对象锁。
  • 由于 JVM 的限制,String 的表示形式必须使用单独的“字符数组”。其他三个字段中的两个字段是使操作占用较少内存的尝试。substring
  • Java 集合类型使用大量内存,因为集合元素不能直接链接。例如,Java中(假设的)单链表集合类的开销为每个列表元素6个单词。相比之下,最佳C/C++链表(即每个元素都有一个“next”指针)每个列表元素的开销为一个单词。

1 - 实际上,平均开销小于此值。JVM只在使用和争用之后“膨胀”了一个锁,类似的技巧也用于身份哈希码。固定开销只有几位。但是,这些位加起来就是一个可测量的更大的对象标头...这才是真正的重点。