From 8f25c25c7ad2815fdbaf896df23c04bc72a7bf4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 15 Dec 2021 12:25:09 +0100 Subject: [PATCH] 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. --- lib/livebook/evaluator.ex | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/livebook/evaluator.ex b/lib/livebook/evaluator.ex index c3803f268..2cc0fc787 100644 --- a/lib/livebook/evaluator.ex +++ b/lib/livebook/evaluator.ex @@ -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