【发布时间】:2015-05-14 17:58:13
【问题描述】:
在 Haskell 中,我创建了一个包含 1000000 个 IntMap 的向量。然后,我使用 Gloss 以从该向量访问随机 intmap 的方式渲染图片。
也就是说,我已经将它们中的每一个都保存在内存中。渲染函数本身非常轻量级,所以性能应该不错。
然而,该程序以 4fps 运行。在分析后,我注意到 95% 的时间都花在了 GC 上。很公平:
GC 正在疯狂地扫描我的向量,即使它从未改变。
有什么方法可以告诉 GHC“这个大值是必需的并且不会改变 - 不要试图在其中收集任何东西”。
编辑:下面的程序足以复制问题。
import qualified Data.IntMap as Map
import qualified Data.Vector as Vec
import Graphics.Gloss
import Graphics.Gloss.Interface.IO.Animate
import System.Random
main = do
let size = 10000000
let gen i = Map.fromList $ zip [mod i 10..0] [0..mod i 10]
let vec = Vec.fromList $ map gen [0..size]
let draw t = do
rnd <- randomIO :: IO Int
let empty = Map.null $ vec Vec.! mod rnd size
let rad = if empty then 10 else 50
return $ translate (20 * cos t) (20 * sin t) (circle rad)
animateIO (InWindow "hi" (256,256) (1,1)) white draw
这会访问一个巨大矢量上的随机地图并绘制一个旋转圆,其半径取决于地图是否为空。
尽管这个逻辑非常简单,但程序在这里却以 1 FPS 左右的速度挣扎。
【问题讨论】:
-
检查 GC 是否真的在收集内存,而不仅仅是浪费时间(应该有一些统计数据显示这一点),只是为了确保没有任何“更新”巨大的向量(即,只需稍作改动即可构建它的副本)。
-
它是可变向量还是不可变向量?可变对象会大大降低 GC 性能。
-
您对垃圾收集器所做工作的描述与我对 GHC 垃圾收集器工作原理的理解不相符。您对“GC 正在疯狂扫描我的向量,即使它从未改变”的说法有多大把握是正确的?
-
其实我不太确定。另外,如果你愿意,我可以尝试制作一个最小的文件来复制问题。
-
一些示例代码确实可以帮助我们帮助您。
标签: haskell optimization garbage-collection ghc