GHC每线程GC策略

时间:2015-05-31 10:56:13

标签: multithreading haskell memory garbage-collection ghc

我有一个Scotty api服务器构造Elasticsearch查询,从ES获取结果并呈现json。

PhoenixGin等其他服务器相比,我使用ES但{{{{}}获得了更高的CPU利用率和服务BloodHound响应的吞吐量3}}和Gin的内存效率优于Phoenix

Scotty的统计数据

 wrk -t30 -c100 -d30s "http://localhost:3000/filters?apid=1&hfa=true"
Running 30s test @ http://localhost:3000/filters?apid=1&hfa=true
  30 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   192.04ms  305.45ms   1.95s    83.06%
    Req/Sec   133.42    118.21     1.37k    75.54%
  68669 requests in 30.10s, 19.97MB read
Requests/sec:   2281.51
Transfer/sec:    679.28KB

这些统计数据在我安装了GHC 7.10.1的Mac上

处理器信息2.5GHx i5
内存信息8GB 1600 Mhz DDR3

基于轻量级线程的GHC并发性让我印象深刻,但内存效率仍然是一个大问题。

分析内存使用量产生了以下统计数据

    39,222,354,072 bytes allocated in the heap
     277,239,312 bytes copied during GC
     522,218,848 bytes maximum residency (14 sample(s))
         761,408 bytes maximum slop
            1124 MB total memory in use (0 MB lost due to fragmentation)

                                     Tot time (elapsed)  Avg pause  Max pause
  Gen  0       373 colls,   373 par    2.802s   0.978s     0.0026s    0.0150s
  Gen  1        14 colls,    13 par    0.534s   0.166s     0.0119s    0.0253s

  Parallel GC work balance: 42.38% (serial 0%, perfect 100%)

  TASKS: 18 (1 bound, 17 peak workers (17 total), using -N4)

  SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)

  INIT    time    0.001s  (  0.008s elapsed)
  MUT     time   31.425s  ( 36.161s elapsed)
  GC      time    3.337s  (  1.144s elapsed)
  EXIT    time    0.000s  (  0.001s elapsed)
  Total   time   34.765s  ( 37.314s elapsed)

  Alloc rate    1,248,117,604 bytes per MUT second

  Productivity  90.4% of total user, 84.2% of total elapsed

gc_alloc_block_sync: 27215
whitehole_spin: 0
gen[0].sync: 8919
gen[1].sync: 30902

Scotty从未超过150 MB,而Phoenix占用的内存要少得多。

我认为GHC使用GC的标记和扫描策略。我也相信使用类似于Erlang VM的每线程增量GC策略可以更好地提高内存效率。

通过解释Don Stewart对Gin的回答,必须有一些方法来改变GHC中的GC策略。

我还注意到,当并发级别较低时,内存使用率保持稳定且非常低,因此我认为只有当并发性很高时,内存使用量才会增加。

解决此问题的任何想法/指示。

1 个答案:

答案 0 :(得分:1)

http://community.haskell.org/~simonmar/papers/local-gc.pdf

Simon Marlow撰写的这篇论文描述了每个线程的本地堆,并声称这是在GHC中实现的。这是2011年的日期。我不能确定这是GHC当前版本的实际情况(即,这是否进入了GHC的发布版本,是否仍然是当前的现状,等等。 ),但似乎我的记忆还没有完全弥补。

我还将指出GHC手册中解释可以调整垃圾收集器的设置的部分:

https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/runtime-control.html#rts-options-gc

特别是,默认情况下GHC使用2空间收集器,但添加-c RTS选项使其使用稍慢的1空间收集器,这应该占用较少的RAM。 (我完全不清楚这些信息适用于哪一代。)

我得到的印象是Simon Marlow是执行大部分RTS工作的人(包括垃圾收集器),所以如果你能在IRC上找到他,他就会问你是否想要直接的真相...