Can I get a list of all currently registered atoms?

My project went through a maximum of 1 million atoms, we increased the limit, but I need to apply common sense to the code that people send regarding list_to_atom and its friends. I would like to start by getting a list of all the registered atoms so that I can see where the biggest offenders are. Is there any way to do this. I have to be creative in how I do this, so as not to try to drop 1-2 million lines into a live console.

+10
source share
4 answers

I'm not sure if there is a way to do this in a live system, but if you can run it in a test environment, you can get the list through a dump. The atom table is near the end of the crash dump format . You can create a crash reset with erlang: halt / 1 , but this will reduce the entire system runtime.

+6
source

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

TL; DR : insert the following line into the Erlang shell of your working node. Read on for an explanation and a short 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 from Ivar Wong :

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

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

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

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

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

There is no easy way to find the number of atoms currently in the atom table * but we can continue to increase the number until we get the badarg error.

So this little module gives you a list of all the 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 this:

 > 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 
+32
source

I dare say that if you use more than 1M atoms, then you are doing something wrong. Atoms should be static as soon as the application starts, or at least is limited to a small number from the top, 3000 or so for a medium-sized application.

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

+3
source

EDITED (wrong answer ..)

You can adjust the number of atoms with +t

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

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

You can track atom statistics with erlang:memory()

0
source

All Articles