Comment by SigmundA
.Net uses real OS threads and that 4mb is the stack not the heap which must be allocated on thread creation. The heap is shared in the process amongst all the threads whereas Erlang is separate lightweight green thread/processes with dynamic heap and stack per process.
.Net originates in the Windows world where new processes are expensive but threads are much cheaper however they still use native stacks for iterop and hardware protection, stack must be contiguous so it is fixed at thread creation this is typical for all native os threads.
Erlang is a VM and runs on top of of processes and threads but exposes its own process model to the language that does not map 1:1 and therefore does not have a fixed stack size allowing many light weight processes. It pays an indirection penalty in performance for this but allows some nice stuff.
Java started with green threads and abandoned them, both .Net and Java use asynchronous concepts instead to get high concurrency now days cooperatively releasing threads and rentering them. There was talk of trying green threads out in .Net and bringing them back in Java for ergonomics compared to async, these green threads would not have such large fixed stacks and many more could be made similar to Erlang processes.
In the end, .NET is going hybrid route. Circa .NET 10/11 Roslyn will stop emitting state machines and something state-machine-like will be produced by the compiler itself iff the asynchronous execution suspends, and will be otherwise practically free.
https://github.com/dotnet/runtime/blob/main/docs/design/spec...
Mind you, short-lived operations are much cheaper with stackless co-routine model like in C#/F# or Rust than spawning an entire, even if virtual, thread/process.