Skip to content

Commit 3aaaf5e

Browse files
committed
Implement the heuristics for garbage collection
1 parent a9d4cdb commit 3aaaf5e

File tree

1 file changed

+67
-9
lines changed

1 file changed

+67
-9
lines changed

lib/iex/lib/iex/history.ex

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,83 @@ defmodule IEx.History do
1414

1515
limit = IEx.Options.get(:history_size)
1616
start_counter = Process.get(:iex_history_start_counter)
17-
should_collect = limit_history(start_counter, counter, limit)
17+
should_collect = limit_history(start_counter, counter, limit, false)
1818
if should_collect do
19-
IO.puts "...collecting garbage"
20-
:erlang.garbage_collect
19+
collect_garbage()
2120
end
2221
end
2322

24-
defp limit_history(_, _, limit) when limit < 0 do
23+
defp limit_history(_, _, limit, _) when limit < 0 do
2524
false
2625
end
2726

28-
defp limit_history(counter, max_counter, limit) when max_counter - counter < limit do
27+
defp limit_history(counter, max_counter, limit, should_collect) when max_counter - counter < limit do
2928
Process.put(:iex_history_start_counter, counter)
30-
true
29+
should_collect
3130
end
3231

33-
defp limit_history(counter, max_counter, limit) do
34-
Process.delete({:iex_history, counter})
35-
limit_history(counter+1, max_counter, limit)
32+
defp limit_history(counter, max_counter, limit, should_collect) do
33+
if not should_collect do
34+
entry = Process.delete({:iex_history, counter})
35+
should_collect = has_binary(entry.result)
36+
else
37+
Process.delete({:iex_history, counter})
38+
end
39+
limit_history(counter+1, max_counter, limit, should_collect)
40+
end
41+
42+
# Checks val and each of its elements (if it is a list or a tuple)
43+
# recursively to see if it has any binaries
44+
defp has_binary(val) do
45+
try do
46+
has_bin(val)
47+
catch
48+
:throw, true -> true
49+
end
50+
end
51+
52+
# Worker function used by has_binary. Throws when the first binary of the
53+
# minimum specified size is found
54+
defp has_bin(val) when is_tuple(val) do
55+
has_bin(val, tuple_size(val)-1)
56+
end
57+
58+
defp has_bin([h|t]) do
59+
has_bin(h)
60+
has_bin(t)
61+
end
62+
63+
defp has_bin(val) when byte_size(val) > 64 do
64+
throw true
65+
end
66+
67+
defp has_bin(_) do
68+
false
69+
end
70+
71+
defp has_bin(_, -1) do
72+
false
73+
end
74+
75+
defp has_bin(tuple, index) do
76+
has_bin(elem(tuple, index))
77+
has_bin(tuple, index-1)
78+
end
79+
80+
# Based on https://github.com/erlang/otp/blob/7dcccee4371477e983f026db9e243cb66900b1ef/lib/stdlib/src/shell.erl#L1401
81+
defp collect_garbage do
82+
:erlang.garbage_collect(self())
83+
try do
84+
:erlang.garbage_collect(Process.whereis(:user))
85+
catch
86+
_, _ -> nil
87+
end
88+
try do
89+
:erlang.garbage_collect(Process.group_leader())
90+
catch
91+
_, _ -> nil
92+
end
93+
:erlang.garbage_collect()
3694
end
3795

3896
### each ###

0 commit comments

Comments
 (0)