了解 F# 内存消耗

Understanding F# memory consumption

我最近一直在玩弄 F#,并在下面写了这个小片段,它只是创建了一些随机的 3d 向量,将它们放入列表中,将每个向量映射到它的长度并将所有这些值相加.

运行 程序(作为 Release Build .exe,非交互式),二进制文件在此特定情况下(10 个 mio 向量)大约消耗 550 MB RAM。一个 Vec3 对象应该占 12 个字节(或者 16 个,假设发生了一些对齐)。即使您使用 32 字节进行粗略计算以计算一些簿记开销(每个对象的字节数 * 10 mio)/ 1024 / 1024),您仍然比实际消耗少 200 MB。天真地我假设最后每个单个有 10 mio * 4 字节,因为 Vec3 对象是 'mapped away'.

到目前为止我的猜测:要么我在某个地方保留了一个(或多个)copy/copies 我的列表但我不知道,或者一些中间结果从未被垃圾收集?我无法想象从 System.Object 继承会带来如此多的开销。 有人能用这个给我指出正确的方向吗?

TiA

type Vec3(x: single, y: single, z:single) = 

    let mag = sqrt(x*x + y*y + z*z)

    member self.Magnitude = mag

    override self.ToString() = sprintf "[%f %f %f]" x y z

let how_much = 10000000

let mutable rng = System.Random()

let sw = new System.Diagnostics.Stopwatch()
sw.Start()

let random_vec_iter len =

    let mutable result = []

    for x = 1 to len do
        let mutable accum = []

        for i = 1 to 3 do
            accum <- single(rng.NextDouble())::accum
        result <- Vec3(accum.[0], accum.[1], accum.[2])::result
    result

sum_len_func = List.reduce (fun x y -> x+y)
let map_to_mag_func = List.map (fun (x:Vec3) -> x.Magnitude)

[<EntryPoint>]
let main argv = 
    printfn "Hello, World"
    let res = sum_len_func (map_to_mag_func (random_vec_iter(how_much)))
    printfn "doing stuff with %i items took %i, result is %f" how_much     (sw.ElapsedMilliseconds) res
    System.Console.ReadKey() |> ignore
    0 // return an integer exit code

首先,你的 vec 是引用类型而不是值类型(不是结构)。因此,您在 12 个字节 (12+16) 的顶部持有一个指针。那么该列表是一个单链表,所以另外 16 个字节用于 .net 引用。然后,您的 List.map 将创建一个中间列表。