Eshell V5.9 (abort with ^G)
1> lists:seq(1,5).
[1,2,3,4,5]
2> L=lists.
lists
3> S=seq.
seq
4> L:S(1,5).
[1,2,3,4,5]
5> L:seq(1,5).
[1,2,3,4,5]
6> L2=list_to_atom("list" ++"s").
lists
7> L2:seq(1,5).
[1,2,3,4,5]
8> apply(list_to_atom("li"++"sts"),seq,[1,5]).
[1,2,3,4,5]
9>
%% list_to_existing_atom demo
Eshell V5.9 (abort with ^G)
1> list_to_existing_atom("player_1").
** exception error: bad argument %尝试调用 list_to_existing_atom("player_1").由于player_1的原子之前没有被创建过
in function list_to_existing_atom/1 %这里报错了 异常是bad argument
called as list_to_existing_atom("player_1")
2> list_to_atom("player_1"). %创建一下player_1
player_1
3> list_to_existing_atom("player_1"). %再次调用list_to_existing_atom就是对的了
player_1
4> list_to_existing_atom("player_2").
** exception error: bad argument
in function list_to_existing_atom/1
called as list_to_existing_atom("player_2")
5> player_2. %也可以这样创建原子
player_2
6> list_to_existing_atom("player_2"). %这时调用也是对的
player_2
7>
我们可以使用 string:tokens( binary_to_list(erlang:system_info(info)),"\n")在shell中看一下atom的使用情况,输出的片段中恰好包含了原子内存使用的情况,当前数量和数量限制;想看完整的输出?穿越到这里
%% list_to_atom demo limit
Eshell V5.9 (abort with ^G)
1> string:tokens( binary_to_list(erlang:system_info(info)),"\n").
["=memory","total: 4331920","processes: 438877",
"processes_used: 438862","system: 3893043","atom: 146321",
"atom_used: 119102","binary: 327936","code: 1929551",
"ets: 123308","=hash_table:atom_tab","size: 4813",
"used: 3508","objs: 6410","depth: 7",
"=index_table:atom_tab","size: 7168","limit: 1048576",
"entries: 6410","=hash_table:module_code","size: 97",
"used: 52","objs: 72","depth: 4","=index_table:module_code",
"size: 1024","limit: 65536","entries: 72",
[...]|...]
2> [list_to_atom("player_"++integer_to_list(Item)) || Item <- lists:seq(1,1000000) ].
[player_1,player_2,player_3,player_4,player_5,player_6,
player_7,player_8,player_9,player_10,player_11,player_12,
player_13,player_14,player_15,player_16,player_17,player_18,
player_19,player_20,player_21,player_22,player_23,player_24,
player_25,player_26,player_27,player_28,player_29|...]
3> string:tokens( binary_to_list(erlang:system_info(info)),"\n").
["=memory","total: 93955448","processes: 37830214",
"processes_used: 37830214","system: 56125234",
"atom: 20296629","atom_used: 20279627","binary: 360656",
"code: 1965264","ets: 124260","=hash_table:atom_tab",
"size: 823117","used: 627221","objs: 1006479","depth: 7",
"=index_table:atom_tab","size: 1006592","limit: 1048576",
"entries: 1006479","=hash_table:module_code","size: 97",
"used: 54","objs: 74","depth: 4","=index_table:module_code",
"size: 1024","limit: 65536","entries: 74",
[...]|...]
4> [list_to_atom("player_"++integer_to_list(Item)) || Item <- lists:seq(1,1000000) ].
[player_1,player_2,player_3,player_4,player_5,player_6,
player_7,player_8,player_9,player_10,player_11,player_12,
player_13,player_14,player_15,player_16,player_17,player_18,
player_19,player_20,player_21,player_22,player_23,player_24,
player_25,player_26,player_27,player_28,player_29|...]
5> string:tokens( binary_to_list(erlang:system_info(info)),"\n").
["=memory","total: 98839096","processes: 42712630",
"processes_used: 42712630","system: 56126466",
"atom: 20296629","atom_used: 20279627","binary: 361888",
"code: 1965264","ets: 124260","=hash_table:atom_tab",
"size: 823117","used: 627221","objs: 1006479","depth: 7",
"=index_table:atom_tab","size: 1006592","limit: 1048576", %注意再次调用的时候这里没有变化
"entries: 1006479","=hash_table:module_code","size: 97",
"used: 54","objs: 74","depth: 4","=index_table:module_code",
"size: 1024","limit: 65536","entries: 74",
[...]|...]
6>
所以在How to Crash Erlang 一文中,无节制使用atom名列前茅:
Run out of atoms. Atoms in Erlang are analogous to symbols in Lisp--that is, symbolic, non-string identifiers that make code more readable, like green or unknown_value--with one exception. Atoms in Erlang are not garbage collected. Once an atom has been created, it lives as long as the Erlang node is running. An easy way to crash the Erlang virtual machine is to loop from 1 to some large number, calling integer_to_list and then list_to_atom on the current loop index. The atom table will fill up with unused entries, eventually bringing the runtime system to halt.
Why is this is allowed? Because garbage collecting atoms would involve a pass over all data in all processes, something the garbage collector was specifically designed to avoid. And in practice, running out of atoms will only happen if you write code that's generating new atoms on the fly.
Note:
Atoms are really nice and a great way to send messages or represent constants. However there are pitfalls to using atoms for too many things: an atom is referred to in an "atom table" which consumes memory (4 bytes/atom in a 32-bit system, 8 bytes/atom in a 64-bit system). The atom table is not garbage collected, and so atoms will accumulate until the system tips over, either from memory usage or because 1048577 atoms were declared.
This means atoms should not be generated dynamically for whatever reason; if your system has to be reliable and user input lets someone crash it at will by telling it to create atoms, you're in serious trouble. Atoms should be seen as tools for the developer because honestly, it's what they are.
Even though bit strings are pretty light, you should avoid using them to tag values. It could be tempting to use string literals to say
{<<"temperature">>,50}
, but always use atoms when doing that. atoms were said to be taking only 4 or 8 bytes in space, no matter how long they are. By using them, you'll have basically no overhead when copying data from function to function or sending it to another Erlang node on another server.
Conversely, do not use atoms to replace strings because they are lighter. Strings can be manipulated (splitting, regular expressions, etc) while atoms can only be compared and nothing else.link :http://learnyousomeerlang.com/starting-out-for-real
Using list_to_atom/1 to construct an atom that is passed to apply/3 like this
apply(list_to_atom("some_prefix"++Var), foo, Args)
is quite expensive and is not recommended in time-critical code.
2012-08-30 更新
Note: If you remember earlier texts, atoms can be used in a limited (though high) number. You shouldn't ever create dynamic atoms. This means naming processes should be reserved to important services unique to an instance of the VM and processes that should be there for the whole time your application runs.
If you need named processes but they are transient or there isn't any of them which can be unique to the VM, it may mean they need to be represented as a group instead. Linking and restarting them together if they crash might be the sane option, rather than trying to use dynamic names.
2014-8-5 11:44:00更新
Intent
Prevent the atom table from filling up
Motivation
The VM will crash if you use too many atoms (by default 1048576)
Atoms are created in many ways:
hand-written code (modules, functions, intentional atoms)
generated code (e.g. ASN.1 compiler, yecc)
reading files (config, file:consult)
parsing (e.g. XML, JSON, ...)
Recommendation
Don’t use list_to_atom/1 and beware of libraries that do (e.g.xmerl). Use list_to_existing_atom/1 or tag tuples with strings/binaries.
如果你在erl_crash.dump看到了"no more index entries in atom_tab (max=1048576)."的信息,那就crashdump_viewer:start/0 检查一下看看什么逻辑创建了那么多的原子吧