🎓 A1Learner
🔍
0 of 46 lessons completed

Elixir Garbage Collection

Garbage collection is the runtime reclaiming memory from values a process no longer uses. It runs on its own, and it can also be forced for one process.

Forcing a collection returns true

The current process asks for a collection. The answer is true.

IO.inspect(:erlang.garbage_collect(self()))
IO.inspect(:erlang.garbage_collect())

A collected worker stays alive

A waiting worker is forced to collect. It stays alive until it gets its stop message.

parent = self()
worker = spawn(fn ->
  send(parent, :ready)
  receive do
    :stop -> :ok
  end
end)
receive do
  :ready -> :ok
end
IO.inspect(:erlang.garbage_collect(worker))
IO.inspect(Process.alive?(worker))
ref = Process.monitor(worker)
send(worker, :stop)
receive do
  {:DOWN, ^ref, :process, ^worker, :normal} -> :ok
end

Dropping a large value keeps the small one

A large list is replaced by a small list. The small list still has three items after a forced collection.

data = Enum.to_list(1..100)
IO.inspect(length(data))
data = [10, 20, 30]
IO.inspect(:erlang.garbage_collect(self()))
IO.inspect(length(data))

Example

parent = self()
worker = spawn(fn ->
  send(parent, :ready)
  receive do
    :stop -> :ok
  end
end)
receive do
  :ready -> :ok
end
IO.inspect(:erlang.garbage_collect(worker))
IO.inspect(Process.alive?(worker))
data = Enum.to_list(1..50)
IO.inspect(length(data))
data = [7, 8]
IO.inspect(:erlang.garbage_collect(self()))
IO.inspect(length(data))
ref = Process.monitor(worker)
send(worker, :stop)
receive do
  {:DOWN, ^ref, :process, ^worker, :normal} -> :ok
end

Key points

  • Collection: :erlang.garbage_collect forces a collection for one process and returns true.
  • Automatic: the runtime also collects on its own without being asked.
  • Dropped value: rebinding a variable to a small value drops the old large value.
  • Kept value: a value still named by a variable is kept, not collected.
  • Worker collection: forcing a collection on a waiting worker leaves the worker alive.
  • Use :erlang.garbage_collect to ask for a collection, never to measure memory.

In this example, a waiting worker is started, then a collection is forced on the worker, then the worker is shown alive, then a large list is built and its length is printed, then the list is replaced by a small list, then a collection is forced on the current process, then the small length is printed, and finally the worker is stopped.

Note

forcing a collection returns true even when there is nothing to reclaim.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What does :erlang.garbage_collect return when it forces a collection?