我最近一直在玩F#,并在下面写下了这个小片段,它只是创建了许多随机的3d vector ,将它们放入列表中,将每个 vector 映射到其长度并将所有这些值求和。

运行该程序(作为Release Build .exe,而不是交互式),在这种特殊情况(10个mio vector )下,二进制文件消耗大约550 MB RAM。一个Vec3对象应占12个字节(假设发生对齐,则为16个字节)。即使您用32个字节进行粗略的数学计算来解决一些簿记开销(每个对象的字节数* 10 mio / 1024/1024),您仍然比实际消耗少200 MB。由于Vec3对象已被“映射”,天真地我假设最后每单有10 mio * 4字节。

到目前为止,我的猜测是:我将某个列表的一份(或几份)副本保存在某个地方,但我不知道这一点,还是某些中间结果从未被垃圾回收?我无法想象从System.Object继承会带来如此多的开销。
有人可以为此指出正确的方向吗?


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)的顶部。然后该列表是单链接列表,因此.net引用还有16个字节。然后,您的List.map将创建一个中间列表。

09-15 21:11