优化Haskell GC的使用
我正在运行一个长期存在的Haskell程序。 运行+RTS -N5 -s -A25M
(我的L3caching的大小)我看到:
715,584,711,208 bytes allocated in the heap 390,936,909,408 bytes copied during GC 4,731,021,848 bytes maximum residency (745 sample(s)) 76,081,048 bytes maximum slop 7146 MB total memory in use (0 MB lost due to fragmentation) Tot time (elapsed) Avg pause Max pause Gen 0 24103 colls, 24103 par 240.99s 104.44s 0.0043s 0.0603s Gen 1 745 colls, 744 par 2820.18s 619.27s 0.8312s 1.3200s Parallel GC work balance: 50.36% (serial 0%, perfect 100%) TASKS: 18 (1 bound, 17 peak workers (17 total), using -N5) SPARKS: 1295 (1274 converted, 0 overflowed, 0 dud, 0 GC'd, 21 fizzled) INIT time 0.00s ( 0.00s elapsed) MUT time 475.11s (454.19s elapsed) GC time 3061.18s (723.71s elapsed) EXIT time 0.27s ( 0.50s elapsed) Total time 3536.57s (1178.41s elapsed) Alloc rate 1,506,148,218 bytes per MUT second Productivity 13.4% of total user, 40.3% of total elapsed
GC时间占总运行时间的87%! 我在一个有大量内存的系统上运行这个,但是当我设置一个高-H
值时,性能变差了。
看来, -H
和-A
控制着第gen 0
的大小,但是我真正想要做的是增加第gen 1
的大小。 做这个的最好方式是什么?
正如卡尔build议,你应该检查空间泄漏的代码。 我会假设你的程序确实需要很多的内存。
该计划花费了2820.18s做重要的GC。 您可以通过减less内存使用量(不是假设情况下)或主要收集数量来降低它。 你有很多可用的RAM,所以你可以尝试-Ffactor
选项 :
-Ffactor [Default: 2] This option controls the amount of memory reserved for the older generations (and in the case of a two space collector the size of the allocation area) as a factor of the amount of live data. For example, if there was 2M of live data in the oldest generation when we last collected it, then by default we'll wait until it grows to 4M before collecting it again.
在你的情况下,有〜3G的实时数据。 默认情况下,当堆增长到6G时,主GC将被触发。 使用-F3
,会在堆长到9G时触发,从而为您节省大约1000秒的CPU时间。
如果大部分实时数据是静态的(例如,永远不会改变或缓慢改变),那么您将对稳定的堆感兴趣。 这个想法是排除主要GC的长期生存数据。 它可以通过使用紧凑的正常forms来实现,尽pipe它尚未被合并到GHC中。