Using an indexed for loop to iterate through an array of functions and invoke them causes a closure allocation for each invocation.
open System
let exampleFunc v = v + 2
let runAll(fArr:(int -> int) array) x =
let mutable n = 0
for i = 0 to fArr.Length - 1 do
n <- n + fArr.[i] x
n
[<EntryPoint>]
let main argv =
let mutable n = 0
let fArr = Array.create 10000 exampleFunc
let runAllClosure = runAll fArr
// snapshot here
Console.ReadLine() |> ignore
for i = 1 to 7 do
n <- n + runAllClosure i
// snapshot here
Console.ReadLine() |> ignore
Console.WriteLine("N is {0}", n)
printfn "%A" argv
0
This shouldn't allocate.
This allocates a closure for each item in the array, whenever runAllClosure is called!
70,000 objects. (7 calls * 1000 size of array)!
This is probably automatically capturing the index for whatever reason, and thus generating a closure.
Swapping to an iterator avoids the allocations.
let runAll(fArr:(int -> int) array) x =
let mutable n = 0
for f in fArr do
n <- n + f x
n
what happens if you don't use the index like:
for i = 0 to fArr.Length - 1 do
n <- n + fArr.[0] x
stil allocating?
@forki - still allocates.
@varon I agree this is a bug. We are getting intermediate code roughly equivalent to InvokeFast2((fun fArr i -> fArr.[i]),fArr,i,x). I don't understand why as yet
THis also avoids the allocations:
let runAll(fArr:(int -> int) array) x =
let mutable n = 0
for i = 0 to fArr.Length - 1 do
let f = fArr.[i]
n <- n + f x
n
I believe I've got this down to
let arr = [|id|]
let b = (arr.[1]) 2
let a = arr.[1] 1
compiling to
int num = array2[1].Invoke(2);
int num2 = FSharpFunc<FSharpFunc<int, int>[], int>.InvokeFast(new a@7(), array2, 1, 1);
The TypedTree.Expr after optimisation are: App(App(get, [arr, 1]), [2]) and App(App(get, []), [arr, 1, 1])
Adding parentheses appears to be enough to avoid this?
Most helpful comment
I believe I've got this down to
compiling to
The TypedTree.Expr after optimisation are:
App(App(get, [arr, 1]), [2])andApp(App(get, []), [arr, 1, 1])Adding parentheses appears to be enough to avoid this?