Trigger the GC after evaluation and intellisense (#807)

This reduces memory consumption by the runtime,
especially when using intellisense features which
may generate a lot of garbage.

There is an odd chance this can generate slow downs
in certain cases but, for that to happen, I would
expect the notebook to either have a lot of data
allocated or many users interacting with it and
triggering completion and other features at the same
time.

We don't worry about the second case because the
goal is to move completion to an ephemeral separate
process anyway, which would remove the need for GC
during completion altogether (and allow several
completions to run concurrently). If this happens,
we can consider moving GC out of the evaluator and
have the session explicitly trigger it once it
terminates a chain of evaluation.

It is also worth triggering the GC whenever
we forget an evaluation context.
This commit is contained in:
José Valim 2021-12-15 12:25:09 +01:00 committed by GitHub
parent a58d0ed0c2
commit 8f25c25c7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -151,11 +151,15 @@ defmodule Livebook.Evaluator do
end
defp call(evaluator, message) do
call_ref = make_ref()
call_ref = Process.monitor(evaluator.pid)
send(evaluator.pid, {:call, evaluator.ref, self(), call_ref, message})
receive do
{^call_ref, reply} -> reply
{^call_ref, reply} ->
reply
{:DOWN, ^call_ref, _, _, reason} ->
exit({reason, {__MODULE__, :call, [evaluator, message]}})
end
end
@ -252,12 +256,15 @@ defmodule Livebook.Evaluator do
metadata = %{evaluation_time_ms: evaluation_time_ms}
send(send_to, {:evaluation_response, ref, output, metadata})
:erlang.garbage_collect(self())
{:noreply, state}
end
defp handle_cast({:forget_evaluation, ref}, state) do
state = Map.update!(state, :contexts, &Map.delete(&1, ref))
Evaluator.ObjectTracker.remove_reference(state.object_tracker, {self(), ref})
:erlang.garbage_collect(self())
{:noreply, state}
end
@ -274,6 +281,7 @@ defmodule Livebook.Evaluator do
send(send_to, {:intellisense_response, ref, request, response})
:erlang.garbage_collect(self())
{:noreply, state}
end