Skip to content

Cache delegates #14582

Closed as not planned
Closed as not planned
@cmeeren

Description

@cmeeren

Consider this code:

open System.Collections.Concurrent

let d = ConcurrentDictionary<string, int>()

let getOrAdd key = d.GetOrAdd(key, fun _ -> 0)

for _ = 0 to 1_000_000 do
  getOrAdd "" |> ignore

When memory profiling (using dotMemory, targeting .NET 7), I see that this allocates 1 million Func<String, Int32> objects:

Allocated type : System.Func<String, Int32>
  Objects : 1000001
  Bytes   : 64000064

Allocated by
   100%  getOrAdd • 61,04 MB / 61,04 MB • global::Program.getOrAdd(String)
     100%  main@ • 61,04 MB / - • <StartupCode$AllocTest>.$Program.main@()
      ►  100%  [AllThreadsRoot] • 61,04 MB / - • [AllThreadsRoot]

This is very surprising to me. (Although I'm no expert in esoteric subjects like compiler optimizations, I consider myself a fairly experienced F# developer.)

I propose that F# caches these delegates. (Note: I am unsure if "delegates" is the right term.)

Possibly related: #910, dotnet/runtime#80430

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions