【问题标题】:D Garbage Collector - estimation about how often and how long run?D 垃圾收集器 - 估计运行频率和运行时间?
【发布时间】:2013-11-14 13:25:56
【问题描述】:

我正在学习 D 语言,我喜欢它的很多功能,但我对 GC 有点怀疑。我想给它机会,但首先我想知道:

  • 如何估计运行频率?
  • 它将运行多长时间?它是否与分配的内存量、托管对象的数量……成正比?

我专门询问当前 D2 运行时的 GC。

我知道 GC 在某些情况下可以带来更好的性能,但是这个例子呢: 想象一个游戏引擎,它在游戏开始时分配了大量内存(数百兆的复杂结构),但在游戏运行时它几乎不进行任何分配/释放。但是有些仍然会发生(例如来自 GUI 中的字符串操作)——那些小事情最终会触发必须扫描所有分配的内存的 GC 吗?据我了解,即使我决定自己管理大部分数据的内存,如果我希望它能够保存对托管内存的任何引用(如字符串),我也必须将范围注册到 GC。

当然,我可以先编程,然后再进行分析,但我希望至少能够提前对性能做出一些估计。比以后诉诸一些变通办法要好。 (在我看来,free lists 之类的解决方案是丑陋的解决方法,无论如何也不能在任何地方使用。)

【问题讨论】:

  • 您可以添加自己的 GC,它是现有的副本,但会发出调试信息
  • 这可能是可能的,但这是分析现有程序的一种方式。我要学习的是 D GC 的一般时间复杂度。因此,在我开始编写一些更大的 D 程序之前,我可以提前决定是否可以对所有事情使用 GC,或者我是否应该更好地自己管理一些内存——在这种情况下如何做才能真正帮助自己。

标签: garbage-collection d


【解决方案1】:

我没有确切的答案,但我可以说:

1) 最确定的来源是 gc 的源代码: https://github.com/D-Programming-Language/druntime/blob/master/src/gc/gc.d (我很确定非常相似的 gcx.d 文件

2) 当你进行 gc 分配时 gc 可以预期运行(好吧,如果它认为它需要分配一个新块,那么它会首先尝试收集现有的东西,但我的经验是在实践中,最好假设每个 new 都可以是一个 gc 集合),在程序终止时,而不是其他任何地方 - 如果你不分配 gc 内存,gc 实际上不会做任何事情。它不会阻止您的程序随机运行。

不过,如果您不知道去哪里看,它可能看起来很随意。检查此页面的底部: http://dlang.org/garbage.html

最常见的就是数组字面量:auto x = [1,2,3];是一个runtime gc分配!也有相当多的 phobos 函数可以进行 gc 分配,尽管不是全部。如果 phobos 函数曾经返回一个数组(包括一个字符串),那么它分配的几率很高 - 如果没有别的,返回值很可能是一个新块,除非你知道你传递了一个缓冲区来接收数据。

也就是说,许多 phobos 实际上是免费分配的,并且随着每个版本的发布而变得更好。我相信所有 std.algorithm 和 std.digest 包现在都是免费分配的,等等。所以你不必把它全部扔掉,只要知道要避免哪些功能。

如果您编写了一个程序并想找到隐藏的分配,我会使用调试器。在主循环之前设置断点。然后在 gc_malloc 和 gc_qalloc 处设置断点并继续。如果它坏了,获取堆栈跟踪,现在您知道以后要避免什么。

如果你的主循环是免费的 gc 分配,它也将是免费的 gc 收集。

3) gc 会扫描所有内存吗?不必要。有一个 noscan 标志表明 gc 实现(参见源代码中的标记函数)可以跳过块。在 druntime/src/rt/lifetime.d 中,你可以看到这个(这里称为 BlkAttr.NO_SCAN)是基于 TypeInfo 设置的。这不是很精确,但我很确定它在诸如大数组分配之类的东西上设置正确。不应扫描您游戏的批量数据资产。

因此,它所花费的时间将与它实际扫描的内存量成正比,这可能比您分配的内存量少很多。

【讨论】:

  • 我查看了gcx.d 和其他文件 - 我可能错过了很多东西,但我的第一印象很糟糕 - 它确实检查了每个扫描区域的每个 字节并继续递归地进入每个发现的托管数据指针......除了NO_SCAN ,是的。但显然 TypeInfo_Classflags 属性返回 1 - 即它应该被扫描。是无条件扫描每个类,还是编译器根据其成员变量为每个具有 flags 属性返回 0/1 的类子类化它?
  • 可以为每个成员变量设置标志,但到目前为止,这还没有完全实现。编译器生成子类类型信息,并且钩子可以更进一步 - object_.d 中的 RTInfo - 如果您自定义它,它不仅对 gc 有用,顺便说一句,但库根本不使用它,它一直在编译器中实现,但现在在主库中设置为 null 已经有一段时间了。 Rainer 做了大部分工作以使其更精确,但它还没有出现在主树中。我不知道整合它的时间表是什么样的。
  • 也就是说,扫描整个班级并不一定是什么大问题,因为你的批量数据可能存储在数组中,将被标记为 NO_SCAN,因此它不会递归进入它们。我的 dom.d 有点占用内存,但 Element 类本身只有大约 64 个字节 - 大多数内存使用是在字符串引用中。
【解决方案2】:

有人已经做过这样的研究,并写了一篇关于它的文章:Real World Comparison, GC vs. Manual Memory Management - Benjamin Thaut

顺便说一句,更多有用的文章可以在这里找到:http://wiki.dlang.org/Articles

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 2012-04-21
    • 2019-10-01
    相关资源
    最近更新 更多