Solution to high memory usage of Erlang Server
Question: The Erlang server has 1 million online users, and 16 GB of memory is quickly swallowed up. The memory occupied by player processes is high.
Solution:
Step 1:
Erlang: system_info (process_count). Check whether the number of processes is normal and whether it exceeds the maximum number of processes on the erlang virtual machine.
Step 2:
View the memory bottleneck of a node
> Erlang: memory ().
[{Total, 2099813400 },
{Processes, 1985444264 },
{Processes_used, 1985276128 },
{System, 114369136 },
{Atom, 4479545 },
{Atom_used, 4477777 },
{Binary, 22756952 },
{Code, 10486554 },
{Ets, 47948808}]
It is shown that most of the memory is consumed by the process, which determines that the process occupies a large amount of memory.
Step 3:
View processes with the highest memory usage
> Spawn (fun ()-> etop: start ([{output, text}, {interval, 1}, {lines, 20}, {sort, memory}]) end ).
(Start etop in output text mode. The interval is 1 second, and the number of output rows is 20 rows, sorted by memory. here, spawn is a new process to output etop data without affecting the erlang shell input .)
Step 4: view the process status with the highest memory usage
> Erlang: process_info (pid (, 0 )).
[{Current_function, {mod_player, send_msg, 2 }},
{Initial_call, {erlang, apply, 2 }},
{Status, waiting },
{Message_queue_len, 0 },
{Messages, []},
{Links, [<0.12570.0>]},
{Dictionary, []},
{Trap_exit, false },
{Error_handler, error_handler },
{Priority, normal },
{Group_leader, <0.46.0> },
{Total_heap_size, 12538050 },
{Heap_size, 12538050 },
{Stack_size, 10122096 },
{Functions, 3795950 },
{Garbage_collection, [{min_bin_vheap_size, 46368 },
{Min_heap_size, 233 },
{Fullsweep_after, 65535 },
{Minor_gcs, 0}]},
{Suspending, []}]
"{Total_heap_size, 12538050}," indicates that the occupied memory is 12358050 words (the 32-bit system word size is 4, and the 64-bit system word size is 8. You can use erlang: system_info (wordsize) view). The 64-bit system has nearly 100 MB, which is too exaggerated!
Step 5:
Manual gc collection, hope the problem can be solved
> Erlang: garbage_collect (pid (, 0 )).
True
Check the process memory again and find that there is no change! Gc has not recycled any resources, so the consumed memory is still playing a role, not recycled!
Step 6:
Do not doubt the system. First, doubt your code.
Observe the code carefully. Its structure is as follows:
Send_msg (Socket, Pid)->
Try
Receive
{Send, Bin}->
...
{Inet_reply, _ Sock, Result}->
...
Catch
_: _->
Send_msg (Sock, Pid)
End.
The purpose is to wait for the data cyclically and then send the data. It uses try... catch to catch exceptions.
This code is not tail recursion! Try... catch stores the corresponding information in the stack. Exception capture must be placed inside the function. Therefore, send_msg finally calls try... catch, not itself, so it is not tail recursion!
The code can be used for verification:
Cat test. erl
-Module (test ).
-Compile ([export_all]).
T1 ()->
Pid = spawn (fun ()-> do_t1 () end ),
Send_msg (Pid, 100000 ).
T2 ()->
Pid = spawn (fun ()-> do_t2 () end ),
Send_msg (Pid, 100000 ).
Send_msg (_ Pid, 0)->
OK;
Send_msg (Pid, N)->
Pid! <2 :( N)>,
Timer: sleep (1, 200 ),
Send_msg (Pid, N-1 ).
Do_t1 ()->
Erlang: garbage_collect (self ()),
Result = erlang: process_info (self (), [memory, garbage_collection]),
Io: format ("~ W ~ N ", [Result]),
Io: format ("backtrace :~ W ~ N ~ N ", [erlang: process_display (self (), backtrace)]),
Try
Receive
_->
Do_t1 ()
End
Catch
_: _->
Do_t1 ()
End.
Do_t2 ()->
Erlang: garbage_collect (self ()),
Result = erlang: process_info (self (), [memory, garbage_collection]),
Io: format ("~ W ~ N ", [Result]),
Io: format ("backtrace :~ W ~ N ~ N ", [erlang: process_display (self (), backtrace)]),
Receive
_->
Do_t2 ()
End.
Version 1: erlctest. erl & erl-eval "test: t1 ()"
Version 2: erlctest. erl & erl-eval "test: t2 ()"
You will see that the call stack of version 1 code is growing, the memory is also growing, and the call address of version 2 function remains unchanged, and the memory has not changed!
Summary:
1. In Server programming, the loop must be tail recursion;
2. Try to use OTP. If you use gen_server to replace the handwritten loop, this problem will be avoided.
Compile and install Erlang R15B on CentOS
Build an Erlang environment in Ubuntu 11.10
Install Erlang through YUM on CentOS 5.7
Erlang --- start parameter learning/Research
Source code compilation and installation of Erlang in CentOS 5.5
Install Erlang 5.8.3 in the source code of Ubuntu 10.10
Install Erlang on CentOS 6.4
Install Erlang R16B in Ubuntu
Erlang details: click here
Erlang: click here
This article permanently updates the link address: