15

我的项目已经超过了最大 1M 个原子,我们已经提高了限制,但是我需要对人们提交的关于 list_to_atom 及其朋友的代码进行一些理智的处理。我想首先获取所有已注册原子的列表,这样我就可以看到最大的违规者在哪里。有没有办法做到这一点。我必须对如何做到这一点有创意,所以我最终不会试图在实时控制台中转储 1-2M 行。

4

4 回答 4

41

您可以使用外部术语格式的未记录功能来获取所有原子。

TL;DR:将以下行粘贴到正在运行的节点的 Erlang shell 中。继续阅读以获取解释和代码的非简洁版本。

(fun F(N)->try binary_to_term(<<131,75,N:24>>) of A->[A]++F(N+1) catch error:badarg->[]end end)(0).

Ivar Vong 的Elixir 版本:

for i <- 0..:erlang.system_info(:atom_count)-1, do: :erlang.binary_to_term(<<131,75,i::24>>)

以外部术语格式编码的 Erlang 术语以字节 131 开头,然后是标识类型的字节,然后是实际数据。我发现EEP-43提到了所有可能的类型,包括类型 byte 75,在外部术语格式的官方文档中ATOM_INTERNAL_REF3没有提到。

对于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,'_',nonode@nohost,'$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
于 2016-01-19T17:31:27.087 回答
8

我不确定是否有办法在实时系统上执行此操作,但如果您可以在测试环境中运行它,您应该能够通过故障转储获取列表。原子表接近故障转储格式的末尾。您可以通过erlang:halt/1创建故障转储,但这会导致整个运行时系统崩溃。

于 2012-11-20T21:35:25.007 回答
3

我敢说,如果你使用超过 100 万个原子,那么你做错了什么。一旦应用程序运行,Atoms 就应该是静态的,或者至少以一些小的数字为上限,对于中型应用程序来说是 3000 左右。

当敌人可以在你的虚拟机中生成原子时要非常小心。特别是像 list_to_atom/1 这样的调用有点危险。

于 2012-11-21T18:32:45.777 回答
0

已编辑(错误答案..)

您可以调整原子数+t

http://www.erlang.org/doc/efficiency_guide/advanced.html

..但我知道很少有必要的用例。

您可以使用以下命令跟踪原子统计信息erlang:memory()

于 2012-11-20T22:11:54.673 回答