我最近一直在玩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将创建一个中间列表。