第一步:
查看进程数目是否正常? erlang:system_info(process_count).
第二步:
查看节点的内存消耗在什么地方?
> erlang:memory().
[{total,2099813400},
{processes,1985444264},
{processes_used,1985276128},
{system,114369136},
{atom,4479545},
{atom_used,4477777},
{binary,22756952},
{code,10486554},
{ets,47948808}]
显示内存大部分消耗在进程上,由此确定是进程占用了大量内存
第三步:
查看哪些进程占用内存最高?
> spawn(fun() -> etop:start([{output, text}, {interval, 1}, {lines, 20}, {sort, memory}]) end).
(以输出text方式启动etop,其间隔为1秒,输出行数为20行,按照内存排序. 这里spawn一个新进程,目的是输出etop数据时不影响erlang shell 输入.)
第四步:
查看占用内存最高的进程状态
> erlang:process_info(pid(0,12571,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},
{reductions,3795950},
{garbage_collection,[{min_bin_vheap_size,46368},
{min_heap_size,233},
{fullsweep_after,65535},
{minor_gcs,0}]},
{suspending,[]}]
其中” {total_heap_size,12538050},” 表示占用内存为 12358050 words(32位系统word size为4,64位系统word size为8, 可以通过erlang:system_info(wordsize) 查看),在64位系统下将近100M, 太夸张了!
第五步:
手动gc回收,希望问题可以解决
> erlang:garbage_collect(pid(0,12571,0)).
true
再次查看进程内存,发现没有任何变化!gc没有回收到任何资源,因此消耗的内存还在发挥作用,没有回收!
第六步:
不要怀疑系统,首先要怀疑自己的代码
认真观察代码,其大致结构如下:
send_msg(Socket, Pid) ->
try
receive
{send, Bin} ->
...
{inet_reply, _Sock, Result} ->
...
catch
_:_ ->
send_msg(Sock, Pid)
end.
其目的是循环等待数据,然后进行发送,其使用了try...catch捕获异常.
这段代码有问题么?
对,这段代码的确有问题, 其不是尾递归! try...catch会在stack中保存相应的信息,异常捕获需要放置在函数内部,所以send_msg最后调用的是try...catch,而不是自身,所以不是尾递归!
可以通过代码得到验证:
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(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.
版本1:erlc test.erl && erl -eval "test:t1()"
版本2:erlc test.erl && erl -eval "test:t2()"
你会看到版本1代码的调用堆栈在不断增长,内存也在增长, 而版本2函数调用地址保持不变,内存也没有发生变化!
总结:
1,服务器编程中,循环一定确保为尾递归
2,善于使用OTP,如果使用gen_server替换手写loop,就不会出现这个问题!
本文属转载
分享到:
相关推荐
标签"千万级性能"提示我们关注的重点在于每种语言在处理大量内存数据时的效率。在实际应用中,除了语言本身的性能外,还要考虑数据结构的选择、算法效率、并行处理能力以及内存管理策略等因素。例如,Erlang的进程...
Erlang核心开发者Lukas Larsson在2014年3月份Erlang Factory上的一个演讲详细介绍了Erlang内存体系的原理以及调优案例 根据siyao zheng博客上听写的资源进行的翻译,大致只翻译了80%但核心部分已经完整,希望对大家...
在Erlang内存管理的背景下,有几个重要的概念需要理解: 1. 堆和栈: Erlang中的每个进程都有自己的内存堆和栈。堆用于存储动态分配的对象,比如元组、列表、字典等;而栈用于存储过程调用和本地变量。 2. ...
1. 确认内存泄漏:使用像top这样的系统监控工具,观察Erlang进程的内存占用情况。如果内存消耗持续升高,那么很可能存在内存泄漏。 2. 进入线上系统:使用Rebar工具,可以方便地管理Erlang项目。通过远程shell命令...
它使用轻量级进程(Lightweight Processes, LWP)实现并发,每个进程占用资源少,易于创建和通信,使得处理大量并发任务变得高效。 2. **错误恢复与容错**:Erlang 采用“Let It Crash”哲学,鼓励程序在遇到错误时...
它负责解释Erlang字节码,提供内存管理、垃圾回收和并发调度等功能。 ### 10. 语言特性 Erlang的语法简洁,支持模式匹配、函数式编程、列表处理和递归等特性。它的动态类型系统和强大的类型推断让代码更加灵活。 ...
- **减少内存消耗**: 通过优化数据结构和算法来降低内存占用。 - **提升响应速度**: 针对瓶颈进行针对性优化,如使用更高效的并发模型。 #### 3. 编码最佳实践 - **模块化**: 将代码组织成多个小而专注的模块,...
在IT行业中,Erlang因其强大的实时性、并发性和内存管理机制而被广泛应用于网络通信、数据库系统以及消息中间件,如RabbitMQ。 RabbitMQ是一款基于AMQP(Advanced Message Queuing Protocol)协议的开源消息队列...
- **OTP(Open Telephony Platform)**:Erlang的核心库,包含大量预先设计的模块,用于处理常见的系统任务,如错误处理、分布式计算和监控。 - **行为模式**:如GenServer、GenEvent和Gen_fsm,它们定义了Erlang中...
Erlang中的模块可以类比于其他语言的类,它包含了一组可以被其他模块调用的函数。函数是模块中的核心,用于执行任务和返回结果。 类型系统是Erlang的另一大特色。Erlang是一种动态类型语言,类型检查在运行时进行,...
安装过程中,你可能会被询问是否要添加Erlang环境变量到PATH,这个选项建议选中,以便在命令行中可以直接使用erl命令。此外,安装路径的选择也很关键,最好选择一个不会频繁变动的位置,以避免日后升级或重装带来的...
- **轻量级进程支持**:每个进程占用的内存非常小,可以创建数十万甚至更多进程。 - **系统信息完善**:ERTS提供了丰富的系统状态和性能监控信息。 - **商用产品的验证**:Erlang已经被众多商业产品采用,并经过了长...
Erlang有活跃的开源社区和丰富的学习资源,包括书籍、教程、以及大量的开源项目。JavaEye的电子书也是其中的一环,提供了专业的深入分析。 #### 17. 系统设计原则 Erlang遵循“让它失败”原则(Let It Crash),...
这个过程可能需要一些时间,因为它会编译整个Erlang虚拟机和标准库。编译完成后,你可以通过运行`make tests`来验证Erlang的正确性。 5. **安装**:最后,使用`make install`将编译好的Erlang二进制文件安装到你的...
erts包含了Erlang虚拟机和其他核心组件,而库则包含了大量的模块和功能,如分布式通信、数据库接口、加密等。 在压缩包中,"COPYRIGHT"文件通常包含了软件的版权信息和许可协议。阅读此文件是了解Erlang的使用权限...
安装Erlang的过程包括下载官方提供的安装包,双击运行并按照向导完成安装,之后设置系统环境变量,将Erlang的bin目录添加到PATH中。最后,通过命令行输入`erl`命令,如果返回相关信息,表明Erlang已成功安装。 总之...
在32位操作系统上运行64位软件通常是不被支持的,所以这里可能指的是64位的Windows用户可以使用这个版本的Erlang。不过,值得注意的是,32位版本的Erlang可能更适合在32位操作系统上运行。 "linux版本"的提法暗示了...
Erlang因其在处理大量并发连接和容错能力上的优秀表现,广泛应用于电信、银行、互联网服务等领域。 在标题"erlang23.2版windows64位.zip"中,我们了解到这是Erlang的一个特定版本——23.2,专为Windows 64位操作...
在IT行业中,Erlang因其强大的实时性和处理大量并发连接的能力而被广泛应用于电信、互联网基础设施和实时系统。RabbitMQ,一个基于Erlang开发的消息队列系统,是实现异步通信的关键组件。 标题中提到的“Erlang官网...
由于其独特的并发处理能力,它在电信、银行、电子商务以及需要大量并发活动处理的系统中被广泛使用。Erlang的设计哲学是创建简单、可扩展、容错的程序,其语法规则相对简单明了,非常适合并行编程和分布式计算。 ##...