Мой проект прошел через максимум 1 млн атомов, мы увеличили предел, но мне нужно применить здравый смысл к коду, который люди отправляют в отношении list_to_atom и его друзей. Я хотел бы начать с получения списка всех зарегистрированных атомов, чтобы я мог видеть, где находятся самые большие правонарушители. Есть какой-либо способ сделать это. Я должен проявить творческий подход к тому, как я это делаю, чтобы не пытаться сбросить 1-2 млн строк в живую консоль.
Могу ли я получить список всех зарегистрированных в настоящее время атомов?
Ответ 1
Я не уверен, есть ли способ сделать это в живой системе, но если вы можете запустить его в тестовой среде, вы сможете получить список через свалку. Таблица атомов ближе к концу формата дампа сбоя. Вы можете создать аварийный сброс с помощью erlang: halt/1, но это приведет к снижению всей системы времени выполнения.
Ответ 2
Вы можете получить все атомы, используя недокументированную особенность внешнего формата термина.
TL; DR: вставьте следующую строку в оболочку Erlang вашего работающего узла. Продолжайте читать для объяснения и краткой версии кода.
(fun F(N)->try binary_to_term(<<131,75,N:24>>) of A->[A]++F(N+1) catch error:badarg->[]end end)(0).
Версия Elixir от Ивара Вонга:
for i <- 0..:erlang.system_info(:atom_count)-1, do: :erlang.binary_to_term(<<131,75,i::24>>)
Термин Эрланга, закодированный во внешнем формате термина, начинается с байта 131, затем байта, идентифицирующего тип, и затем фактических данных. Я обнаружил, что в EEP-43 упоминаются все возможные типы, включая ATOM_INTERNAL_REF3
с байтом типа 75, который не упоминается в официальной документации внешнего формата термина.
Для ATOM_INTERNAL_REF3
данные представляют собой индекс в таблице атомов, закодированный как 24-разрядное целое число. Мы можем легко создать такой двоичный файл: <<131,75,N:24>>
Например, в моей Erlang VM false
кажется нулевой атом в таблице атомов:
> binary_to_term(<<131,75,0:24>>).
false
Не существует простого способа найти количество атомов, находящихся в настоящее время в таблице атомов * но мы можем продолжать увеличивать число, пока не получим ошибку badarg
.
Итак, этот маленький модуль дает вам список всех атомов:
-module(all_atoms).
-export([all_atoms/0]).
atom_by_number(N) ->
binary_to_term(<<131,75,N:24>>).
all_atoms() ->
atoms_starting_at(0).
atoms_starting_at(N) ->
try atom_by_number(N) of
Atom ->
[Atom] ++ atoms_starting_at(N + 1)
catch
error:badarg ->
[]
end.
Вывод выглядит так:
> all_atoms:all_atoms().
[false,true,'_',[email protected],'$end_of_table','','fun',
infinity,timeout,normal,call,return,throw,error,exit,
undefined,nocatch,undefined_function,undefined_lambda,
'DOWN','UP','EXIT',aborted,abs_path,absoluteURI,ac,accessor,
active,all|...]
> length(v(-1)).
9821
* В Erlang/OTP 20.0 вы можете вызвать erlang:system_info(atom_count)
:
> length(all_atoms:all_atoms()) == erlang:system_info(atom_count).
true
Ответ 3
Я смею сказать, что если вы используете более 1M атомов, то вы делаете что-то неправильно. Атомы должны быть статичными, как только приложение запускается или, по крайней мере, сверху ограничено небольшим числом, 3000 или около того для приложения среднего размера.
Будьте очень осторожны, когда враг может генерировать атомы в вашем vm. особенно вызовы типа list_to_atom/1 несколько опасны.
Ответ 4
EDITED (неправильный ответ..)
Вы можете отрегулировать число атомов с помощью +t
http://www.erlang.org/doc/efficiency_guide/advanced.html
.. но я знаю очень мало случаев использования, когда это необходимо.
Вы можете отслеживать статистику атома с помощью erlang:memory()