I’m just learning elixir for fun , and I would love to understand a little bit more about the memory allocations that are made during the following code snippet taken from the Mix OTP tutorial:
It really depends on how deep you want to go. From the 10,000 foot above, you can consider all values are allocated on the per-process heap and are immutable. So there will not be cyclic references, GC is straight forward, and closure is easy to implement.
Of cause there are exceptions, but the native code hide the ugly parts and maintain the happy illusion.
#1: yes, the closure captures its environment. Rebinding client after the call to Task.Supervisor.start_child won’t change the value the child process sees.
#2: the thing that’s returned from :gen_tcp.accept is usually a “port”; short short version it’s a way to name the thing that’s actually holding the OS socket. Calling controlling_process tells the port that it should send messages etc to the newly-started task instead of the process that originally called :gen_tcp.accept.
#3: there’s no state attached to the module KVServer, so asking whether there’s a second “copy” of it isn’t particularly meaningful. There’s some very tricky corner-cases around hot-code reloading that make calling serve(client) different from calling KVServer.serve(client) (even from inside a function defined in KVServer!) but most people will never encounter them.