Understanding F # Memory Consumption

I've been playing with F # lately and wrote this little snippet below, it just creates a series of randomized 3d vectors, puts them into a list, matches each vector in length and sums all those values.

Running the program (as a Build.exe release, not an interactive one), the binary consumes in this particular case (10 million vectors) about 550MB of RAM. A single Vec3 object should account for 12 bytes (or 16, assuming some alignment is performed). Even if you do some rough math with 32 bytes to account for some storage overhead (bytes per object * 10M / 1024/1024), you're still 200MB of actual consumption. I naively believe that in the end I will have 10 mio * 4 bytes per single, since the Vec3 objects are "imprinted".

So far, my guess is: Either I leave one (or more) copy / copies of my list somewhere and I don't know about it, or are some intermediate results never going to be garbage collected? I can't imagine that inheriting from System.Object comes with a lot of overhead. Can anyone point me in the right direction?

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

      

+3


source to share


1 answer


First, your vec is a ref type, not a value type (not a struct). This way you are holding the pointer on top of your 12 bytes (12 + 16). The list is then a singly linked list, so 16 more bytes for the .net ref. Then your List.map will create an intermediate list.



+3


source







All Articles