@@ -14,25 +14,83 @@ defmodule IEx.History do
14
14
15
15
limit = IEx.Options . get ( :history_size )
16
16
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 )
18
18
if should_collect do
19
- IO . puts "...collecting garbage"
20
- :erlang . garbage_collect
19
+ collect_garbage ( )
21
20
end
22
21
end
23
22
24
- defp limit_history ( _ , _ , limit ) when limit < 0 do
23
+ defp limit_history ( _ , _ , limit , _ ) when limit < 0 do
25
24
false
26
25
end
27
26
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
29
28
Process . put ( :iex_history_start_counter , counter )
30
- true
29
+ should_collect
31
30
end
32
31
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 ( )
36
94
end
37
95
38
96
### each ###
0 commit comments