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

前端 未结 4 1161
梦如初夏
梦如初夏 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:40

    EDITED (wrong answer..)

    You can adjust number of atoms with +t

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

    ..but I know very few use cases when it is necessary.

    You can track atom stats with erlang:memory()

    0 讨论(0)
  • 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
    
    0 讨论(0)
  • 2021-01-11 10:50

    I dare say that if you use more than 1M atoms, then you are doing something wrong. Atoms are intended to be static as soon as the application runs or at least upper bounded by some small number, 3000 or so for a medium sized application.

    Be very careful when an enemy can generate atoms in your vm. especially calls like list_to_atom/1 is somewhat dangerous.

    0 讨论(0)
  • 2021-01-11 10:53

    I'm not sure if there's a way to do it on a live system, but if you can run it in a test environment you should be able to get a list via crash dump. The atom table is near the end of the crash dump format. You can create a crash dump via erlang:halt/1, but that will bring down the whole runtime system.

    0 讨论(0)
提交回复
热议问题