Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 如何在Haskell中控制5GB堆?_Performance_Haskell_Garbage Collection_Memory Management - Fatal编程技术网

Performance 如何在Haskell中控制5GB堆?

Performance 如何在Haskell中控制5GB堆?,performance,haskell,garbage-collection,memory-management,Performance,Haskell,Garbage Collection,Memory Management,目前,我正在试验一个用Snap编写的小型Haskell web服务器,它可以加载并向客户机提供大量数据。我很难控制服务器进程。在随机时刻,进程会占用大量CPU数秒到数分钟,并且对客户端请求不负责任。有时内存使用在几秒钟内达到数百兆字节的峰值(有时下降) 希望有人对使用大量内存的长时间运行的Haskell进程有更多的经验,并能给我一些建议,使其更加稳定。我已经调试了好几天了,现在我开始有点绝望了 我的设置概述如下: 在服务器启动时,我将大约5 GB的数据读入内存中一个类似data.Map的大(嵌

目前,我正在试验一个用Snap编写的小型Haskell web服务器,它可以加载并向客户机提供大量数据。我很难控制服务器进程。在随机时刻,进程会占用大量CPU数秒到数分钟,并且对客户端请求不负责任。有时内存使用在几秒钟内达到数百兆字节的峰值(有时下降)

希望有人对使用大量内存的长时间运行的Haskell进程有更多的经验,并能给我一些建议,使其更加稳定。我已经调试了好几天了,现在我开始有点绝望了

我的设置概述如下:

  • 在服务器启动时,我将大约5 GB的数据读入内存中一个类似data.Map的大(嵌套)结构中。嵌套映射是严格值映射,映射内的所有值都是数据类型,其所有字段也都被设置为严格值。我花了很多时间来确保没有未经评估的恶棍留下。导入(取决于我的系统负载)大约需要5-30分钟。奇怪的是,连续运行的波动比我预期的要大,但这是另一个问题

  • 大数据结构存在于“TVar”中,由Snap服务器生成的所有客户端线程共享。客户端可以使用小型查询语言请求数据的任意部分。数据请求量通常很小(高达300kb左右),并且只涉及数据结构的一小部分。所有只读请求都使用“readTVarIO”完成,因此它们不需要任何STM事务

  • 服务器使用以下标志启动:+RTS-N-I0-qg-qb。这将以多线程模式启动服务器,禁用空闲时间和并行GC。这似乎大大加快了进程

服务器大部分运行没有任何问题。然而,客户机请求时不时地超时,CPU峰值达到100%(甚至超过100%),并持续这样做很长一段时间。同时,服务器不再响应请求

我能想到的几个可能导致CPU使用率的原因:

  • 这个请求需要很多时间,因为有很多工作要做。这是不太可能的,因为在以前的运行中已经证明非常快的请求有时会发生这种情况(fast是指20-80ms左右)

  • 在处理数据并将其发送到客户端之前,仍然需要计算一些未评估的thunk。这也不太可能,原因与前一点相同

  • 不知怎的,垃圾收集开始了,开始扫描我的整个5GB堆。我可以想象这会占用很多时间

问题是,我不知道如何确切地了解到底发生了什么,以及如何应对。因为导入过程需要很长时间,所以分析结果没有显示任何有用的内容。似乎无法从代码中有条件地打开和关闭探查器

我个人怀疑GC是这里的问题。我正在使用GHC7,它似乎有很多选项来调整GC的工作方式


当使用具有通常非常稳定的数据的大堆时,您建议使用什么样的GC设置?

大内存使用率和偶尔出现的CPU峰值几乎肯定是GC的原因。您可以通过使用RTS选项(如
-B
)查看情况是否确实如此,这会在有主要集合时导致GHC发出蜂鸣音,
-t
会在事后告诉您统计信息(特别是,查看GC时间是否真的很长)或
-Dg
,这会打开GC调用的调试信息(尽管您需要使用
-debug
进行编译)

您可以采取以下几项措施来缓解此问题:

  • 在初次导入数据时,GHC浪费了大量的时间来增加堆。您可以通过指定一个大的
    -H
    命令GHC立即获取所需的所有内存

  • 包含稳定数据的大型堆将升级为旧一代。如果使用
    -G
    增加代数,则可以将稳定数据放在最旧的、很少使用GC的代中,而上面有更传统的新旧堆

  • 根据应用程序其余部分的内存使用情况,您可以使用
    -F
    来调整旧一代在再次收集之前GHC将增长多少。您可以调整此参数以使其不被垃圾收集

  • 如果没有写操作,并且您有一个定义良好的接口,那么让这个内存不受GHC管理(使用C FFI)可能是值得的,这样就不可能有超级GC了


这些都是推测,因此请使用您的特定应用程序进行测试。

我遇到了一个非常类似的问题,即1.5GB的嵌套映射堆。默认情况下,打开空闲GC时,我会在每个GC上获得3-4秒的冻结时间,关闭空闲GC(+RTS-I0),我会在几百次查询后获得17秒的冻结时间,从而导致客户端超时

我的“解决方案”第一个是增加客户端超时时间,并要求人们容忍98%的查询时间大约为500毫秒,但大约2%的查询速度会非常慢。然而,为了寻求更好的解决方案,我最终运行了两台负载平衡服务器,每200次查询就将它们从集群中脱机,然后重新运行


雪上加霜的是,这是对一个原始Python程序的重写,它从来没有出现过这样的问题。公平地说,我们确实获得了大约40%的性能提升,非常容易的并行化和更稳定的代码库。但是这个讨厌的GC问题…

Hmmm…。有趣的是……你运行这个服务器应用程序的盒子有多少RAM我的机器上总共有8GB的内存。这应该足够了。是的