从源编译时的空间行为与链接到包时的空间行为不同

时间:2019-06-17 20:57:03

标签: haskell

此代码是否泄漏取决于我如何编译相同的RWS实现:

import           Control.Monad         (replicateM_)
import qualified Control.Monad.RWS.CPS as RWS
import           Data.Monoid           (Sum (..))
-- import qualified RWS

{-# ann module "HLint: ignore Use camelCase" #-}

count_a_lot :: Int -> RWS.RWS () (Sum Int) () ()
count_a_lot = flip replicateM_ count

count :: RWS.RWS () (Sum Int) () ()
count = RWS.tell . Sum $ 1

main :: IO ()
main = print . snd $ RWS.evalRWS (count_a_lot 10000000) () ()

我尝试了两种使用CPS版本的RWS的方法:

  • import qualified Control.Monad.RWS.CPS as RWS使用nixpkgs中的writer-cps-transformers软件包。
  • import qualified RWS使用Internal.hs,原样复制为RWS.hs到与上面粘贴的文件相同的本地目录中。

如果我编译上面的代码并运行它,我可以看到它在恒定空间中运行。

hs2ps, constant space

如果我更改导入以编译并链接RWS.hs的副本

import           Control.Monad (replicateM_)
-- import qualified Control.Monad.RWS.CPS as RWS
import           Data.Monoid   (Sum (..))
import qualified RWS

我遇到了空间泄漏。黑色的固定器是(103)<*>.\,蓝色的固定器是SYSTEM

enter image description here

为什么会这样?还是我该如何最好地调试它?

在两种情况下,我都使用-Wall -O2 -prof -fprof-auto -rtsopts -fexternal-interpreter用ghc(无阴谋)进行编译。如果相关,我可以发布更详细的编译器调用和输出行。

使用ghc-8.4.4transformers-0.5.5.0writer-cps-transformers-0.1.1.4。我知道这些版本不是最新版本,但是我有兴趣知道正在发生的事情,而不是解决实际的泄漏,因此我认为这些版本无关紧要。

1 个答案:

答案 0 :(得分:3)

罪魁祸首实际上是配置文件系统。请注意,您实际上并不需要-prof来检测空间泄漏-RTS选项-s可以打印出“总内存”测量值而无需它。从科学上讲,空间泄漏会使程序变慢得多,您可以感觉到它。有了这一准备,我发现禁用-prof可以将“本地”版本的内存使用减少到2MB(与“库”版本相同),并保留约1.9GB的可用空间。

配置文件会使速度变慢的原因是因为GHC也拒绝优化。它无法再积极地重组您编写的代码,因为成本中心暗示着代码的某种结构,并且有时优化后成本中心没有合适的位置,从而阻碍了该优化。要确切地知道这里出了什么问题,就需要知道构建库所用的标志,但是从高级的角度来看,writer-cps-transformers库的构建要比{{ 1}}文件。 RWS.hs是一个非常激进的分析选项,它可以轻易破坏很多优化。如果我使用由-fprof-auto构建的writer-cps-transformers,则会遇到相同的问题。如果我使用-fprof-auto而不进行概要分析或使用RWS.hs之类的较弱功能,则可以解决此问题。