GHC垃圾收集的RTS选项

我有一个Haskell程序处理一个文本文件,并build立一个Map (数百万元)。 整个事情可以运行2-3分钟。 我发现调整-H和-A选项对运行时间有很大的影响。

有关于RTS的这个function的文档 ,但是对于我来说这是一个很难读懂的东西,因为我不知道GC理论中的algorithm和术语。 我正在寻找一个较less的技术解释,最好是特定于Haskell / GHC。 有没有关于select这些选项的明智价值的参考?

编辑:这是代码,它build立一个给定的单词列表trie。

 buildTrie :: [B.ByteString] -> MyDFA buildTrie l = fst3 $ foldl' step (emptyDFA, B.empty, 1) $ sort $ map B.reverse l where step :: (MyDFA , B.ByteString, Int) -> B.ByteString -> (MyDFA , B.ByteString, Int) step (dfa, lastWord, newIndex) newWord = (insertNewStates, newWord, newIndex + B.length newSuffix) where (pref, lastSuffix, newSuffix) = splitPrefix lastWord newWord branchPoint = transStar dfa pref --new state labels for the newSuffix path newStates = [newIndex .. newIndex + B.length newSuffix - 1] --insert newStates insertNewStates = (foldl' (flip insertTransition) dfa $ zip3 (branchPoint:init newStates) (B.unpack newSuffix) newStates) 

一般来说,垃圾收集是一个时空权衡。 给GC更多的空间,这将花费更less的时间。 游戏中还有(很多)其他因素,特别是caching,但空间/时间的权衡是最重要的。

权衡是这样的:程序分配内存直到达到一定的限制(由GC的自动调整参数决定,或通过RTS选项明确)。 达到限制时,GC跟踪程序当前正在使用的所有数据,并回收不再需要的数据所使用的所有内存。 您可以延迟这个过程的时间越长,在此期间越多的数据将变得无法访问(“死亡”),因此GC避免跟踪该数据。 延迟GC的唯一方法是使更多的内存可用于分配; 因此更多的内存等于更less的GC,等于更低的GC开销。 粗略地说,GHC的-H选项可以让您设置GC使用的内存量的下限,这样可以降低GC开销。

GHC使用分代GC ,这是基本scheme的一种优化,其中堆被分成两代或更多代。 对象被分配到“年轻”一代,而那些足够长的被提升到“旧”一代(在2代设置中)。 年轻一代的收集比老一代要频繁得多,这个想法是“大多数的对象年轻化”,所以年轻一代的collections便宜(他们没有追踪太多的数据),但是他们回收了很多的记忆。 粗略地说,-A选项设定了年轻一代的规模 – 也就是在收集年轻一代之前分配的内存量。

-A的缺省值为512k:保持年轻一代比二级caching小是一个好主意,如果超过二级caching大小,性能一般会下降。 但是在相反的方向上工作是GC空间/时间的折中:通过减lessGC的工作量,使用非常大的年轻一代的规模可能会超过caching的好处。 这并不总是会发生,这取决于应用程序的dynamic性,这使GC很难自动调整自己。 -H选项也增加了年轻一代的大小,所以也可能对高速caching使用产生不利影响。

底线是:玩弄选项,看看有什么作品。 如果你有足够的内存空间,你或许可以通过使用-A或-H来提高性能,但不一定。

对于较小的数据集,可能会重现这个问题,在那里可以更容易地看到正在发生的事情。 特别是,我build议对分析有一定的了解:

  • “ 真实世界”Haskell书中的分析章节提供了一个很好的概述,包括可能遇到的典型问题
  • GHC手册中的分析章节logging了可用的function

然后,检查你看到的内存configuration文件是否符合你的期望(你不需要知道所有的分析选项来获得有用的图表)。 严格foldl'与一个非严格元组作为累加器的组合将是我首先要看的:如果元组的组成部分不是强制的,那recursion正在build立未被评估的expression式。

顺便说一句,你可以build立一个很好的直觉关于这样的事情,试图通过手工评估你的代码真正微小的数据集。 几次迭代就足以查看expression式是否得到评估,或以适合您的应用程序的方式保持未评估。