I wanted to show to a colleague that you can allocate more than 2GB of ram, so I made a little test application.
let mega = 1 <<< 20
let konst x y = x
let allocate1MB _ = Array.init mega (konst 0uy)
let memoryHog = Array.Parallel.init 8192 allocate1MB
printfn "I'm done..."
System.Console.ReadKey() |> ignore
this works and you actually see the process happily hogging away at the system's memory. However, it takes somewhat long - hence the Array.Parallel.init
.
I noticed, that the same code does not work, if I write it with
let allocate1MB _ = Array.zeroCreate mega
More precisely, no data is allocated and it takes no time.
So thus my question; What is the difference in semantics between Array.zeroCreate and Array.init?
I understand that Array.init
would run my konst 0uy
function each time, which would explain the time difference. But why does Array.zeroCreate
not allocate the memory?
From the FSharp.Core sources:
let inline init (count:int) (f: int -> 'T) =
if count < 0 then invalidArg "count" InputMustBeNonNegativeString
let arr = (zeroCreateUnchecked count : 'T array)
for i = 0 to count - 1 do
arr.[i] <- f i
arr
let zeroCreate count =
if count < 0 then invalidArg "count" (SR.GetString(SR.inputMustBeNonNegative))
Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
let inline zeroCreateUnchecked (count:int) =
(# "newarr !0" type ('T) count : 'T array #)
As you can see, the both functions use zeroCreateUnchecked
under the hood, which is compiled to newarr
IL that is supposed to push a new array onto the stack.
The fact that this does not consume any memory in your case might indicate that some kind of optimization is responsible. I think either JIT or the compiler is removing this operation since the created array is never used, and that obviously does not happen in the case of Array.init
.