Step 1:
Check whether the number of processes is normal? Erlang: system_info (process_count ).
Step 2:
Check the node memory consumption?
> 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:
Check which processes occupy the highest memory?
> 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.
Is there a problem with this code?
Yes, this code is indeed faulty. It 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: ERlC test. erl & Erl-eval "test: T1 ()"
Version 2: ERlC test. 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. Good at using OTP. If you use gen_server to replace the handwritten loop, this problem will not occur!