Can I get a list of all currently-registered atoms?

前端 未结 4 1160
梦如初夏
梦如初夏 2021-01-11 10:07

My project has blown through the max 1M atoms, we\'ve cranked up the limit, but I need to apply some sanity to the code that people are submitting with regard to list_to_ato

4条回答
  •  有刺的猬
    2021-01-11 10:45

    You can get hold of all atoms by using an undocumented feature of the external term format.

    TL;DR: Paste the following line into the Erlang shell of your running node. Read on for explanation and a non-terse version of the code.

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

    Elixir version by Ivar Vong:

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

    An Erlang term encoded in the external term format starts with the byte 131, then a byte identifying the type, and then the actual data. I found that EEP-43 mentions all the possible types, including ATOM_INTERNAL_REF3 with type byte 75, which isn't mentioned in the official documentation of the external term format.

    For ATOM_INTERNAL_REF3, the data is an index into the atom table, encoded as a 24-bit integer. We can easily create such a binary: <<131,75,N:24>>

    For example, in my Erlang VM, false seems to be the zeroth atom in the atom table:

    > binary_to_term(<<131,75,0:24>>).
    false
    

    There's no simple way to find the number of atoms currently in the atom table*, but we can keep increasing the number until we get a badarg error.

    So this little module gives you a list of all atoms:

    -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.
    

    The output looks like:

    > 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
    

    * In Erlang/OTP 20.0, you can call erlang:system_info(atom_count):

    > length(all_atoms:all_atoms()) == erlang:system_info(atom_count).
    true
    

提交回复
热议问题