2011-08-01 39 views
8

以下两个方案只对变量ST相差的严格性标志为什么strict标志会增加内存使用量?

$猫testStrictL.hs

module Main (main) where 

import qualified Data.Vector as V 
import qualified Data.Vector.Generic as GV 
import qualified Data.Vector.Mutable as MV 

len = 5000000 

testL = do 
    mv <- MV.new len 
    let go i = do 
      if i >= len then return() else 
      do let st = show (i+10000000) -- no strictness flag 
       MV.write mv i st 
       go (i+1) 
    go 0 
    v <- GV.unsafeFreeze mv :: IO (V.Vector String) 
    return v 

main = 
    do 
    v <- testL 
    print (V.length v) 
    mapM_ print $ V.toList $ V.slice 4000000 5 v 

$猫testStrictS.hs

module Main (main) where 

import qualified Data.Vector as V 
import qualified Data.Vector.Generic as GV 
import qualified Data.Vector.Mutable as MV 

len = 5000000 

testS = do 
    mv <- MV.new len 
    let go i = do 
      if i >= len then return() else 
      do let !st = show (i+10000000) -- this has the strictness flag 
       MV.write mv i st 
       go (i+1) 
    go 0 
    v <- GV.unsafeFreeze mv :: IO (V.Vector String) 
    return v 

main = 
    do 
    v <- testS 
    print (V.length v) 
    mapM_ print $ V.toList $ V.slice 4000000 5 v 

上编译和运行这两个程序Ubuntu 10.10与ghc 7.03 我收到以下结果

 
$ ghc --make testStrictL.hs -O3 -rtsopts 
[2 of 2] Compiling Main    (testStrictL.hs, testStrictL.o) 
Linking testStrictL ... 
$ ghc --make testStrictS.hs -O3 -rtsopts 
[2 of 2] Compiling Main    (testStrictS.hs, testStrictS.o) 
Linking testStrictS ... 
$ ./testStrictS +RTS -sstderr 
./testStrictS +RTS -sstderr 
5000000 
"14000000" 
"14000001" 
"14000002" 
"14000003" 
"14000004" 
    824,145,164 bytes allocated in the heap 
    1,531,590,312 bytes copied during GC 
    349,989,148 bytes maximum residency (6 sample(s)) 
     1,464,492 bytes maximum slop 
      656 MB total memory in use (0 MB lost due to fragmentation) 

    Generation 0: 1526 collections,  0 parallel, 5.96s, 6.04s elapsed 
    Generation 1:  6 collections,  0 parallel, 2.79s, 4.36s elapsed 

    INIT time 0.00s ( 0.00s elapsed) 
    MUT time 1.77s ( 2.64s elapsed) 
    GC time 8.76s (10.40s elapsed) 
    EXIT time 0.00s ( 0.13s elapsed) 
    Total time 10.52s (13.04s elapsed) 

    %GC time  83.2% (79.8% elapsed) 

    Alloc rate 466,113,027 bytes per MUT second 

    Productivity 16.8% of total user, 13.6% of total elapsed 

$ ./testStrictL +RTS -sstderr 
./testStrictL +RTS -sstderr 
5000000 
"14000000" 
"14000001" 
"14000002" 
"14000003" 
"14000004" 
     81,091,372 bytes allocated in the heap 
    143,799,376 bytes copied during GC 
     44,653,636 bytes maximum residency (3 sample(s)) 
     1,005,516 bytes maximum slop 
       79 MB total memory in use (0 MB lost due to fragmentation) 

    Generation 0: 112 collections,  0 parallel, 0.54s, 0.59s elapsed 
    Generation 1:  3 collections,  0 parallel, 0.41s, 0.45s elapsed 

    INIT time 0.00s ( 0.03s elapsed) 
    MUT time 0.12s ( 0.18s elapsed) 
    GC time 0.95s ( 1.04s elapsed) 
    EXIT time 0.00s ( 0.06s elapsed) 
    Total time 1.06s ( 1.24s elapsed) 

    %GC time  89.1% (83.3% elapsed) 

    Alloc rate 699,015,343 bytes per MUT second 

    Productivity 10.9% of total user, 9.3% of total elapsed 

难道有人请解释为什么严格标志似乎会导致程序使用如此多的内存?这个简单的例子来自我试图理解为什么我的程序 在读取500万行的大文件和创建记录的向量 时使用如此多的内存。

+1

严格限制执行的顺序 - 这是它的重点。这限制了优化者的选择。不是一个答案,因为我的Haskell-fu不够强大,无法确切地说出发生了什么,但我的猜测是严格性会阻止优化,从而允许在'go'尾递归内更有效地重用内存循环。 – Steve314

+0

如果您使用的是最新版本的GHC,则可以尝试指定应该使用LLVM后端,而不是原始GHC后端。这可能不会影响最高级别的优化决策,但它会为低级别生成的代码选择完全不同的优化器。 – Steve314

回答

8

这里的问题是主要是您使用的String(其是用于[Char]别名)型,由于其为单Char s的非严格列表表示需要每个字符5个字的存储器堆(还参见this blog article一些内存占用比较)

在懒情况下,基本上存储一个未计算的形实转换指向(共享的)评价函数show . (+10000000)和变化整数,而在严格的情况下,完整的字符串组成的8个字符似乎是物化的(通常,爆炸模式只会强制最外层的列表 - 构造函数:,即懒惰的第一个字符String,待评估),这需要更多的堆空间,字符串变得越长。

存储5000000 String长度为8的长度为8的字符串因此需要5000000 * 8 * 5 = 200000000个字,其在32位上对应于大约〜763MB。如果共享Char数字,则只需要3/5,即约458 MiB,这似乎与您观察到的内存开销相匹配。

如果您将String替换为更紧凑的东西,例如Data.ByteString.ByteString,您会注意到与使用普通String相比,内存开销将降低大约一个数量级。

+0

感谢您的答案hvr。使用Data.ByteString.Char8或Data.Text时,我没有得到较低的内存开销,只有大约一半,但仍然有很大的改进。 – user449050

+1

@ user449050,我只在64位上试过,其中的改进有点大幅,我没有考虑到在32位上这不是同一个因子。 – hvr

相关问题