为什么这里的早期术语没有被垃圾收集?

dspyz

如果我将Kolakoski序列定义

kolakoski :: () -> [Int]
kolakoski () = 1 : 2 : helper ()
  where
    helper () = 2 : concat (zipWith replicate (helper ()) (cycle [1, 2]))

并找到第500,000,000项

kolakoski () !! 500000000

我发现,使用ghc -O编译时,这会迅速消耗大量内存。但是关闭优化后,它几乎不使用任何东西。哪个优化导致了此问题,以及如何将其关闭?

泽塔

让我们比较实际数字。kolakoski如果不进行优化运行,您的版本使用大约70k:

$ ghc --make Kolakoski-Unit && ./Kolakoski-Unit + RTS -s
2
 堆中分配了288,002,359,096字节
   在GC期间复制了1,343,933,816字节
          67,576字节的最大驻留时间(422个样本)
          最大斜率52,128字节
               正在使用2 MB的总内存(由于碎片丢失了0 MB)

                                    总时间(经过)平均暂停最大暂停
  Gen 0 551615 cols,0 par 1.89s 2.30s 0.0000s 0.0001s
  Gen 1422 colls,0 par 0.02s 0.02s 0.0001s 0.0001s

  初始化时间0.00s(经过0.00s)
  MUT时间37.34秒(经过37.25秒)
  GC时间1.91秒(经过2.33秒)
  退出时间0.00s(经过0.00s)
  总时间39.25秒(经过39.58秒)

  %GC时间4.9%(经过5.9%)

  每MUT秒分配7,712,197,063字节的速率

  生产力,占总用户的95.1%,占总使用时间的94.3%

通过优化,它可以使用约4GB(尽管任务管理器中的实际内存使用量约为6GB)。

$ ghc --make Kolakoski-Unit -O && ./Kolakoski-Unit + RTS -s
2
  堆中分配了64,000,066,608字节
  GC期间复制了27,971,527,816字节
   3,899,031,480字节最大驻留时间(34个样本)
      最大斜率91,679,728字节
            正在使用9549 MB的总内存(由于碎片丢失了0 MB)

                                    总时间(经过)平均暂停最大暂停
  Gen 0 122806 colls,0 par 8.67s 9.48s 0.0001s 0.0148s
  Gen 1 34列,0杆11.55s 69.78s 2.0524s 56.2970s

  初始化时间0.00s(经过0.00s)
  MUT时间8.80秒(经过8.43秒)
  GC时间20.22s(经过79.26s)
  退出时间0.03s(经过0.89s)
  总时间29.05s(经过88.58s)

  %GC时间69.6%(已用89.5%)

  每个MUT秒的分配速率7,275,318,406字节

  生产力占总用户的30.4%,占总使用时间的10.0%

如果我们使用基于列表的版本而不进行优化,则内存消耗与启用了优化的内存消耗非常相似:

kolakoskiList :: [Int]
kolakoskiList = 1 : 2 : helper 
  where
    helper = 2 : concat (zipWith replicate helper (cycle [1, 2]))
$ ghc --make Kolakoski-List && ./Kolakoski-List + RTS -s
2
  堆中分配了96,000,143,328字节
  GC期间复制了26,615,974,536字节
   3,565,429,808字节最大驻留时间(34个样本)
      最大斜率83,610,688字节
            正在使用的总内存为8732 MB(由于碎片丢失了0 MB)

                                    总时间(经过)平均暂停最大暂停
  Gen 0 184252 cols,0 par 9.98s 10.16s 0.0001s 0.0006s
  Gen 1 34列,0杆10.45s 21.61s 0.6357s 12.0792s

  初始化时间0.00s(经过0.00s)
  MUT时间12.02秒(经过11.88秒)
  GC时间20.44s(经过31.77s)
  退出时间0.05秒(经过0.69秒)
  总时间32.50秒(经过44.34秒)

  %GC时间62.9%(已消耗71.7%)

  每个MUT秒的分配速率7,989,608,807字节

  生产力,占总用户的37.1%,占总使用时间的27.2%

现在,我们可以检查GHC标志参考以获取自动设置为的标志-O由于列表版本似乎与优化版本具有相同的功能,因此人们可能会认为GHC可以转换kolakoskikolakoskiList

kolakoskiOptimized _ = kolakoskiList

让我们在核心中进行检查-ddump-simpl -dsupress-all

==================== Tidy Core ====================
Result size of Tidy Core = {terms: 45, types: 30, coercions: 0}

kolakoski
kolakoski =
  \ ds_d10r ->
    case ds_d10r of _ { () ->
    : (I# 1)
      (: (I# 2)
         (letrec {
            helper_aNo
            helper_aNo =
              \ ds1_d10s ->
                case ds1_d10s of _ { () ->
                : (I# 2)
                  (concat
                     (zipWith
                        (replicate) (helper_aNo ()) (cycle (: (I# 1) (: (I# 2) ([]))))))
                }; } in
          helper_aNo ()))
    }

main
main = print $fShowInt (!! (kolakoski ()) (I# 500000000))

main
main = runMainIO main

即使您不熟悉GHC的核心,也可以看到它kolakoski与原始版本基本相同。现在将其与-O -ddump-simpl -dsupress-all

==================== Tidy Core ====================
Result size of Tidy Core = {terms: 125, types: 102, coercions: 9}

kolakoski6
kolakoski6 = I# 1

kolakoski5
kolakoski5 = I# 2

Rec {
go_r1NG
go_r1NG =
  \ ds_a14B _ys_a14C ->
    case ds_a14B of _ {
      [] -> [];
      : ipv_a14H ipv1_a14I ->
        case _ys_a14C of _ {
          [] -> [];
          : ipv2_a14O ipv3_a14P ->
            case ipv_a14H of _ { I# n#_a13J ->
            case tagToEnum# (<=# n#_a13J 0) of _ {
              False ->
                let {
                  lvl2_s1N3
                  lvl2_s1N3 = : ipv2_a14O ([]) } in
                letrec {
                  xs_a1LH
                  xs_a1LH =
                    \ m_a1LO ->
                      case tagToEnum# (<=# m_a1LO 1) of _ {
                        False -> : ipv2_a14O (xs_a1LH (-# m_a1LO 1));
                        True -> lvl2_s1N3
                      }; } in
                ++ (xs_a1LH n#_a13J) (go_r1NG ipv1_a14I ipv3_a14P);
              True -> ++ ([]) (go_r1NG ipv1_a14I ipv3_a14P)
            }
            }
        }
    }
end Rec }

lvl_r1NH
lvl_r1NH = : kolakoski5 ([])

lvl1_r1NI
lvl1_r1NI = : kolakoski6 lvl_r1NH

Rec {
xs'_r1NJ
xs'_r1NJ = ++ lvl1_r1NI xs'_r1NJ
end Rec }

Rec {
kolakoski3
kolakoski3 = : kolakoski5 kolakoski4

kolakoski4
kolakoski4 = go_r1NG kolakoski3 xs'_r1NJ
end Rec }

kolakoski2
kolakoski2 = : kolakoski5 kolakoski3

kolakoski1
kolakoski1 = : kolakoski6 kolakoski2

kolakoski
kolakoski = \ ds_d13p -> case ds_d13p of _ { () -> kolakoski1 }

该版本包含几个顶级CAF,在程序的整个生命周期中都将保留这些CAF因此,您实际上会生成最多500,000,000个值的列表并将其保存

现在,那里发生了什么?函数内部的内容向外浮动。让我们再次检查标志引用。有一个有前途的标志,它暗示-O

-ffull-laziness启用完全懒惰(向外浮动绑定)。由暗示-O

这就是导致您出现问题的标志。确实,您可以使用ghc --make -O -fno-full-laziness Kolakoski-Unit.hs来获取原始的内存消耗:

$ ghc --make Kolakoski-Unit.hs -O -fno-full-laziness && ./Kolakoski-Unit + RTS -s
2
 堆中分配的192,001,417,688字节
     GC期间复制了637,962,464字节
          66,104字节最大驻留时间(151个样本)
          最大43448个字节
               正在使用2 MB的总内存(由于碎片丢失了0 MB)

                                    总时间(经过)平均暂停最大暂停
  Gen 0 368364 colls,0 par 1.34s 1.32s 0.0000s 0.0002s
  Gen 1151列,0 par 0.00s 0.01s 0.0001s 0.0003s

  初始化时间0.00s(经过0.00s)
  MUT时间27.89s(经过28.13s)
  GC时间1.34秒(经过1.33秒)
  退出时间0.00s(经过0.00s)
  总时间29.25秒(经过29.46秒)

  %GC时间4.6%(经过4.5%)

  每个MUT秒分配的速率6,884,084,443字节

  生产力占总用户的95.4%,占总使用时间的94.7%

相关问题

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么这个对象没有得到垃圾收集?

来自分类Dev

为什么活动没有收集到垃圾?

来自分类Dev

为什么操作系统没有垃圾收集器?

来自分类Dev

垃圾收集和使用-为什么在“ using {}”块之后没有释放内存?

来自分类Dev

垃圾收集和使用-为什么在“ using {}”块之后没有释放内存?

来自分类Dev

为什么这里没有提出StopIteration?

来自分类Dev

为什么这里没有提出StopIteration?

来自分类Dev

为什么这里没有呈现“选择”?

来自分类Dev

为什么大型垃圾收集的速度比小型垃圾收集慢?

来自分类Dev

为什么Jdeveloper没有列出早期的IOS版本?

来自分类Dev

为什么不收集我的.NET垃圾?

来自分类Dev

为什么不收集我的.NET垃圾?

来自分类Dev

Bash这里的文件没有输出,为什么?

来自分类Dev

为什么 sharedPreference 没有保存在这里?

来自分类Dev

为什么垃圾收集器不收集Tasks对象

来自分类Dev

为什么box.com上没有我的Word文件的早期版本?

来自分类Dev

为什么垃圾收集器不会破坏弹簧容器

来自分类Dev

为什么Shake建议禁用空闲垃圾收集?

来自分类Dev

为什么要禁用垃圾收集器?

来自分类Dev

为什么对WeakRef对象的WeakReference不进行垃圾收集?

来自分类Dev

未在C#中进行垃圾收集。为什么?

来自分类Dev

为什么垃圾收集器在取消分配之前等待?

来自分类Dev

为什么不收集这个Git commit垃圾?

来自分类Dev

Android 5:没有更多垃圾收集消息吗?

来自分类Dev

什么是constant_score,没有术语

来自分类Dev

为什么fastmember在这里似乎没有比反思更快?

来自分类Dev

为什么这里没有遵循运算符优先级?

来自分类Dev

为什么在没有身体的情况下写在这里?

来自分类Dev

为什么这里没有将带符号的char转换为unsigned int?

Related 相关文章

  1. 1

    为什么这个对象没有得到垃圾收集?

  2. 2

    为什么活动没有收集到垃圾?

  3. 3

    为什么操作系统没有垃圾收集器?

  4. 4

    垃圾收集和使用-为什么在“ using {}”块之后没有释放内存?

  5. 5

    垃圾收集和使用-为什么在“ using {}”块之后没有释放内存?

  6. 6

    为什么这里没有提出StopIteration?

  7. 7

    为什么这里没有提出StopIteration?

  8. 8

    为什么这里没有呈现“选择”?

  9. 9

    为什么大型垃圾收集的速度比小型垃圾收集慢?

  10. 10

    为什么Jdeveloper没有列出早期的IOS版本?

  11. 11

    为什么不收集我的.NET垃圾?

  12. 12

    为什么不收集我的.NET垃圾?

  13. 13

    Bash这里的文件没有输出,为什么?

  14. 14

    为什么 sharedPreference 没有保存在这里?

  15. 15

    为什么垃圾收集器不收集Tasks对象

  16. 16

    为什么box.com上没有我的Word文件的早期版本?

  17. 17

    为什么垃圾收集器不会破坏弹簧容器

  18. 18

    为什么Shake建议禁用空闲垃圾收集?

  19. 19

    为什么要禁用垃圾收集器?

  20. 20

    为什么对WeakRef对象的WeakReference不进行垃圾收集?

  21. 21

    未在C#中进行垃圾收集。为什么?

  22. 22

    为什么垃圾收集器在取消分配之前等待?

  23. 23

    为什么不收集这个Git commit垃圾?

  24. 24

    Android 5:没有更多垃圾收集消息吗?

  25. 25

    什么是constant_score,没有术语

  26. 26

    为什么fastmember在这里似乎没有比反思更快?

  27. 27

    为什么这里没有遵循运算符优先级?

  28. 28

    为什么在没有身体的情况下写在这里?

  29. 29

    为什么这里没有将带符号的char转换为unsigned int?

热门标签

归档